From ef9e3851b5e3e36cf76db0afcad7ad17922075f3 Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 09:29:32 -0600 Subject: [PATCH 1/7] removed beefy rpc folder --- client/consensus/beefy-etf/rpc/Cargo.toml | 32 -- client/consensus/beefy-etf/rpc/src/lib.rs | 288 ------------------ .../beefy-etf/rpc/src/notification.rs | 39 --- 3 files changed, 359 deletions(-) delete mode 100644 client/consensus/beefy-etf/rpc/Cargo.toml delete mode 100644 client/consensus/beefy-etf/rpc/src/lib.rs delete mode 100644 client/consensus/beefy-etf/rpc/src/notification.rs diff --git a/client/consensus/beefy-etf/rpc/Cargo.toml b/client/consensus/beefy-etf/rpc/Cargo.toml deleted file mode 100644 index 47a033e..0000000 --- a/client/consensus/beefy-etf/rpc/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "sc-consensus-beefy-etf-rpc" -version = "13.0.0" -authors.workspace = true -edition.workspace = true -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository.workspace = true -description = "RPC for the BEEFY Client gadget for substrate" -homepage = "https://substrate.io" - -[lints] -workspace = true - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } -log = { workspace = true, default-features = true } -parking_lot = "0.12.1" -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } -sc-consensus-beefy-etf = { path = "..", features = ["bls-experimental"] } -sp-consensus-beefy-etf = { path = "../../../../primitives/consensus/beefy-etf", features = ["bls-experimental"] } -sc-rpc = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } - -[dev-dependencies] -serde_json = { workspace = true, default-features = true } -sc-rpc = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", features = ["test-helpers"] } -substrate-test-runtime-client = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -tokio = { version = "1.22.0", features = ["macros"] } diff --git a/client/consensus/beefy-etf/rpc/src/lib.rs b/client/consensus/beefy-etf/rpc/src/lib.rs deleted file mode 100644 index 68f4c03..0000000 --- a/client/consensus/beefy-etf/rpc/src/lib.rs +++ /dev/null @@ -1,288 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! RPC API for BEEFY. - -#![warn(missing_docs)] - -use parking_lot::RwLock; -use std::sync::Arc; - -use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; -use sp_runtime::traits::Block as BlockT; - -use futures::{task::SpawnError, FutureExt, StreamExt}; -use jsonrpsee::{ - core::async_trait, - proc_macros::rpc, - types::{ErrorObject, ErrorObjectOwned}, - PendingSubscriptionSink, -}; -use log::warn; - -use sc_consensus_beefy_etf::communication::notification::{ - BeefyBestBlockStream, BeefyVersionedFinalityProofStream, -}; - -mod notification; - -#[derive(Debug, thiserror::Error)] -/// Top-level error type for the RPC handler -pub enum Error { - /// The BEEFY RPC endpoint is not ready. - #[error("BEEFY RPC endpoint not ready")] - EndpointNotReady, - /// The BEEFY RPC background task failed to spawn. - #[error("BEEFY RPC background task failed to spawn")] - RpcTaskFailure(#[from] SpawnError), -} - -/// The error codes returned by jsonrpc. -pub enum ErrorCode { - /// Returned when BEEFY RPC endpoint is not ready. - NotReady = 1, - /// Returned on BEEFY RPC background task failure. - TaskFailure = 2, -} - -impl From for ErrorCode { - fn from(error: Error) -> Self { - match error { - Error::EndpointNotReady => ErrorCode::NotReady, - Error::RpcTaskFailure(_) => ErrorCode::TaskFailure, - } - } -} - -impl From for ErrorObjectOwned { - fn from(error: Error) -> Self { - let message = error.to_string(); - let code = ErrorCode::from(error); - ErrorObject::owned(code as i32, message, None::<()>) - } -} - -// Provides RPC methods for interacting with BEEFY. -#[rpc(client, server)] -pub trait BeefyApi { - /// Returns the block most recently finalized by BEEFY, alongside its justification. - #[subscription( - name = "beefy_subscribeJustifications" => "beefy_justifications", - unsubscribe = "beefy_unsubscribeJustifications", - item = Notification, - )] - fn subscribe_justifications(&self); - - /// Returns hash of the latest BEEFY finalized block as seen by this client. - /// - /// The latest BEEFY block might not be available if the BEEFY gadget is not running - /// in the network or if the client is still initializing or syncing with the network. - /// In such case an error would be returned. - #[method(name = "beefy_getFinalizedHead")] - async fn latest_finalized(&self) -> Result; -} - -/// Implements the BeefyApi RPC trait for interacting with BEEFY. -pub struct Beefy { - finality_proof_stream: BeefyVersionedFinalityProofStream, - beefy_best_block: Arc>>, - executor: SubscriptionTaskExecutor, -} - -impl Beefy -where - Block: BlockT, -{ - /// Creates a new Beefy Rpc handler instance. - pub fn new( - finality_proof_stream: BeefyVersionedFinalityProofStream, - best_block_stream: BeefyBestBlockStream, - executor: SubscriptionTaskExecutor, - ) -> Result { - let beefy_best_block = Arc::new(RwLock::new(None)); - - let stream = best_block_stream.subscribe(100_000); - let closure_clone = beefy_best_block.clone(); - let future = stream.for_each(move |best_beefy| { - let async_clone = closure_clone.clone(); - async move { *async_clone.write() = Some(best_beefy) } - }); - - executor.spawn("substrate-rpc-subscription", Some("rpc"), future.map(drop).boxed()); - Ok(Self { finality_proof_stream, beefy_best_block, executor }) - } -} - -#[async_trait] -impl BeefyApiServer - for Beefy -where - Block: BlockT, -{ - fn subscribe_justifications(&self, pending: PendingSubscriptionSink) { - let stream = self - .finality_proof_stream - .subscribe(100_000) - .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); - - sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); - } - - async fn latest_finalized(&self) -> Result { - self.beefy_best_block.read().as_ref().cloned().ok_or(Error::EndpointNotReady) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use codec::{Decode, Encode}; - use jsonrpsee::{core::EmptyServerParams as EmptyParams, RpcModule}; - use sc_consensus_beefy_etf::{ - communication::notification::BeefyVersionedFinalityProofSender, - justification::BeefyVersionedFinalityProof, - }; - use sp_consensus_beefy_etf::{known_payloads, Payload, SignedCommitment}; - use sp_runtime::traits::{BlakeTwo256, Hash}; - use substrate_test_runtime_client::runtime::Block; - - fn setup_io_handler() -> (RpcModule>, BeefyVersionedFinalityProofSender) { - let (_, stream) = BeefyBestBlockStream::::channel(); - setup_io_handler_with_best_block_stream(stream) - } - - fn setup_io_handler_with_best_block_stream( - best_block_stream: BeefyBestBlockStream, - ) -> (RpcModule>, BeefyVersionedFinalityProofSender) { - let (finality_proof_sender, finality_proof_stream) = - BeefyVersionedFinalityProofStream::::channel(); - - let handler = - Beefy::new(finality_proof_stream, best_block_stream, sc_rpc::testing::test_executor()) - .expect("Setting up the BEEFY RPC handler works"); - - (handler.into_rpc(), finality_proof_sender) - } - - #[tokio::test] - async fn uninitialized_rpc_handler() { - let (rpc, _) = setup_io_handler(); - let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; - let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#; - let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); - - assert_eq!(expected_response, response); - } - - #[tokio::test] - async fn latest_finalized_rpc() { - let (sender, stream) = BeefyBestBlockStream::::channel(); - let (io, _) = setup_io_handler_with_best_block_stream(stream); - - let hash = BlakeTwo256::hash(b"42"); - let r: Result<(), ()> = sender.notify(|| Ok(hash)); - r.unwrap(); - - // Verify RPC `beefy_getFinalizedHead` returns expected hash. - let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; - let expected = "{\ - \"jsonrpc\":\"2.0\",\ - \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ - \"id\":1\ - }"; - let not_ready = "{\ - \"jsonrpc\":\"2.0\",\ - \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ - \"id\":1\ - }"; - - let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); - while std::time::Instant::now() < deadline { - let (response, _) = io.raw_json_request(request, 1).await.expect("RPC requests work"); - if response != not_ready { - assert_eq!(response, expected); - // Success - return; - } - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - } - - panic!( - "Deadline reached while waiting for best BEEFY block to update. Perhaps the background task is broken?" - ); - } - - #[tokio::test] - async fn subscribe_and_unsubscribe_with_wrong_id() { - let (rpc, _) = setup_io_handler(); - // Subscribe call. - let _sub = rpc - .subscribe_unbounded("beefy_subscribeJustifications", EmptyParams::new()) - .await - .unwrap(); - - // Unsubscribe with wrong ID - let (response, _) = rpc - .raw_json_request( - r#"{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":["FOO"],"id":1}"#, - 1, - ) - .await - .unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; - - assert_eq!(response, expected); - } - - fn create_finality_proof() -> BeefyVersionedFinalityProof { - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - BeefyVersionedFinalityProof::::V1(SignedCommitment { - commitment: sp_consensus_beefy_etf::Commitment { - payload, - block_number: 5, - validator_set_id: 0, - }, - signatures: vec![], - }) - } - - #[tokio::test] - async fn subscribe_and_listen_to_one_justification() { - let (rpc, finality_proof_sender) = setup_io_handler(); - - // Subscribe - let mut sub = rpc - .subscribe_unbounded("beefy_subscribeJustifications", EmptyParams::new()) - .await - .unwrap(); - - // Notify with finality_proof - let finality_proof = create_finality_proof(); - let r: Result<(), ()> = finality_proof_sender.notify(|| Ok(finality_proof.clone())); - r.unwrap(); - - // Inspect what we received - let (bytes, recv_sub_id) = sub.next::().await.unwrap().unwrap(); - let recv_finality_proof: BeefyVersionedFinalityProof = - Decode::decode(&mut &bytes[..]).unwrap(); - assert_eq!(&recv_sub_id, sub.subscription_id()); - assert_eq!(recv_finality_proof, finality_proof); - } -} diff --git a/client/consensus/beefy-etf/rpc/src/notification.rs b/client/consensus/beefy-etf/rpc/src/notification.rs deleted file mode 100644 index f732317..0000000 --- a/client/consensus/beefy-etf/rpc/src/notification.rs +++ /dev/null @@ -1,39 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use codec::Encode; -use serde::{Deserialize, Serialize}; - -use sp_runtime::traits::Block as BlockT; - -/// An encoded finality proof proving that the given header has been finalized. -/// The given bytes should be the SCALE-encoded representation of a -/// `sp_consensus_beefy_etf::VersionedFinalityProof`. -#[derive(Clone, Serialize, Deserialize)] -pub struct EncodedVersionedFinalityProof(sp_core::Bytes); - -impl EncodedVersionedFinalityProof { - pub fn new( - finality_proof: sc_consensus_beefy_etf::justification::BeefyVersionedFinalityProof, - ) -> Self - where - Block: BlockT, - { - EncodedVersionedFinalityProof(finality_proof.encode().into()) - } -} From 5d489e4dae2d8555c48e4ab223dc9d33434fb439 Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 09:58:59 -0600 Subject: [PATCH 2/7] remove beefy-etf workspace member --- Cargo.lock | 5950 ++++------------- Cargo.toml | 1 - client/consensus/beefy-etf/Cargo.toml | 72 - client/consensus/beefy-etf/README.md | 373 -- client/consensus/beefy-etf/src/aux_schema.rs | 106 - .../beefy-etf/src/communication/gossip.rs | 796 --- .../beefy-etf/src/communication/mod.rs | 160 - .../src/communication/notification.rs | 55 - .../beefy-etf/src/communication/peers.rs | 127 - .../incoming_requests_handler.rs | 223 - .../src/communication/request_response/mod.rs | 114 - .../outgoing_requests_engine.rs | 280 - client/consensus/beefy-etf/src/error.rs | 64 - client/consensus/beefy-etf/src/import.rs | 200 - .../consensus/beefy-etf/src/justification.rs | 251 - client/consensus/beefy-etf/src/keystore.rs | 642 -- client/consensus/beefy-etf/src/lib.rs | 760 --- client/consensus/beefy-etf/src/metrics.rs | 345 - client/consensus/beefy-etf/src/round.rs | 524 -- client/consensus/beefy-etf/src/tests.rs | 1594 ----- client/consensus/beefy-etf/src/worker.rs | 1851 ----- 21 files changed, 1255 insertions(+), 13233 deletions(-) delete mode 100644 client/consensus/beefy-etf/Cargo.toml delete mode 100644 client/consensus/beefy-etf/README.md delete mode 100644 client/consensus/beefy-etf/src/aux_schema.rs delete mode 100644 client/consensus/beefy-etf/src/communication/gossip.rs delete mode 100644 client/consensus/beefy-etf/src/communication/mod.rs delete mode 100644 client/consensus/beefy-etf/src/communication/notification.rs delete mode 100644 client/consensus/beefy-etf/src/communication/peers.rs delete mode 100644 client/consensus/beefy-etf/src/communication/request_response/incoming_requests_handler.rs delete mode 100644 client/consensus/beefy-etf/src/communication/request_response/mod.rs delete mode 100644 client/consensus/beefy-etf/src/communication/request_response/outgoing_requests_engine.rs delete mode 100644 client/consensus/beefy-etf/src/error.rs delete mode 100644 client/consensus/beefy-etf/src/import.rs delete mode 100644 client/consensus/beefy-etf/src/justification.rs delete mode 100644 client/consensus/beefy-etf/src/keystore.rs delete mode 100644 client/consensus/beefy-etf/src/lib.rs delete mode 100644 client/consensus/beefy-etf/src/metrics.rs delete mode 100644 client/consensus/beefy-etf/src/round.rs delete mode 100644 client/consensus/beefy-etf/src/tests.rs delete mode 100644 client/consensus/beefy-etf/src/worker.rs diff --git a/Cargo.lock b/Cargo.lock index e0bde2a..b232e56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -12,22 +12,13 @@ dependencies = [ "regex", ] -[[package]] -name = "addr2line" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" -dependencies = [ - "gimli 0.27.3", -] - [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.31.1", + "gimli", ] [[package]] @@ -43,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -53,7 +44,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher 0.4.4", + "cipher", "cpufeatures", ] @@ -65,10 +56,10 @@ checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", - "cipher 0.4.4", + "cipher", "ctr", "ghash", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -81,7 +72,7 @@ dependencies = [ "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -99,36 +90,6 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - [[package]] name = "anyhow" version = "1.0.93" @@ -245,7 +206,7 @@ dependencies = [ "ark-serialize", "ark-snark", "ark-std", - "blake2 0.10.6", + "blake2", "derivative", "digest 0.10.7", "sha2 0.10.8", @@ -588,9 +549,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "asn1-rs" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -598,31 +559,31 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "syn 2.0.89", + "synstructure", ] [[package]] name = "asn1-rs-impl" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.89", ] [[package]] @@ -636,25 +597,105 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.2.0", + "futures-lite 2.5.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock 3.4.0", + "blocking", + "futures-lite 2.5.0", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.4.0", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.5.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.28", + "slab", + "socket2 0.4.10", + "waker-fn", +] + [[package]] name = "async-io" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ - "async-lock", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite", + "futures-lite 2.5.0", "parking", - "polling", + "polling 3.7.4", "rustix 0.38.41", "slab", "tracing", "windows-sys 0.59.0", ] +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + [[package]] name = "async-lock" version = "3.4.0" @@ -663,14 +704,121 @@ checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", - "pin-project-lite 0.2.15", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.4.0", + "blocking", + "futures-lite 2.5.0", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel 2.3.1", + "async-io 2.4.0", + "async-lock 3.4.0", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.3.1", + "futures-lite 2.5.0", + "rustix 0.38.41", + "tracing", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io 2.4.0", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.41", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-std" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 2.4.0", + "async-lock 3.4.0", + "async-process", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 2.5.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-std-resolver" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abef525d07400182ad6d48b3097d8e88a40aed1f3a6e80f221b2b002cfad608" +dependencies = [ + "async-std", + "async-trait", + "futures-io", + "futures-util", + "hickory-resolver", + "pin-utils", + "socket2 0.5.7", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", @@ -679,15 +827,32 @@ dependencies = [ [[package]] name = "asynchronous-codec" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" dependencies = [ "bytes", "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.15", + "pin-project-lite", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.12", + "log", + "url", ] [[package]] @@ -702,11 +867,11 @@ version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "addr2line 0.24.2", + "addr2line", "cfg-if", "libc", "miniz_oxide", - "object 0.36.5", + "object", "rustc-demangle", "windows-targets 0.52.6", ] @@ -760,9 +925,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -770,15 +935,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - [[package]] name = "binary-merkle-tree" version = "13.0.0" @@ -798,15 +954,6 @@ dependencies = [ "log", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitcoin-internals" version = "0.2.0" @@ -847,18 +994,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" -dependencies = [ - "byte-tools", - "crypto-mac 0.7.0", - "digest 0.8.1", - "opaque-debug 0.2.3", -] - [[package]] name = "blake2" version = "0.10.6" @@ -879,37 +1014,13 @@ dependencies = [ "constant_time_eq 0.3.1", ] -[[package]] -name = "blake2s_simd" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq 0.3.1", -] - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq 0.3.1", -] - [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -918,7 +1029,20 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.5.0", + "piper", ] [[package]] @@ -933,12 +1057,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -948,15 +1066,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "build-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" -dependencies = [ - "semver 0.6.0", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -969,12 +1078,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytemuck" version = "1.20.0" @@ -993,56 +1096,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" -[[package]] -name = "c2-chacha" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80" -dependencies = [ - "cipher 0.2.5", - "ppv-lite86", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.23", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cc" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -1063,28 +1122,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862" -dependencies = [ - "byteorder", - "keystream", -] - -[[package]] -name = "chacha20" -version = "0.9.1" +name = "chacha20" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher 0.4.4", + "cipher", "cpufeatures", ] @@ -1096,60 +1145,11 @@ checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher 0.4.4", + "cipher", "poly1305", "zeroize", ] -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "cid" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b68e3193982cd54187d71afdb2a271ad4cf8af157858e9cb911b91321de143" -dependencies = [ - "core2", - "multibase", - "multihash 0.17.0", - "serde", - "unsigned-varint", -] - -[[package]] -name = "cid" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd94671561e36e4e7de75f753f577edafb0e7c05d6e4547229fdf7938fbcd2c3" -dependencies = [ - "core2", - "multibase", - "multihash 0.18.1", - "serde", - "unsigned-varint", -] - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "cipher" version = "0.4.4" @@ -1170,26 +1170,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "common" version = "0.1.0" @@ -1220,19 +1200,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "console" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.52.0", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -1277,12 +1244,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation" version = "0.9.4" @@ -1308,15 +1269,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "cpp_demangle" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" -dependencies = [ - "cfg-if", -] - [[package]] name = "cpufeatures" version = "0.2.15" @@ -1327,125 +1279,12 @@ dependencies = [ ] [[package]] -name = "cranelift-bforest" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70" -dependencies = [ - "cranelift-entity", -] - -[[package]] -name = "cranelift-codegen" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220" -dependencies = [ - "bumpalo", - "cranelift-bforest", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-entity", - "cranelift-isle", - "gimli 0.27.3", - "hashbrown 0.13.2", - "log", - "regalloc2 0.6.1", - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cranelift-codegen-meta" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da" -dependencies = [ - "cranelift-codegen-shared", -] - -[[package]] -name = "cranelift-codegen-shared" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8" - -[[package]] -name = "cranelift-entity" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0" -dependencies = [ - "serde", -] - -[[package]] -name = "cranelift-frontend" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d" -dependencies = [ - "cranelift-codegen", - "log", - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cranelift-isle" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba" - -[[package]] -name = "cranelift-native" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00" -dependencies = [ - "cranelift-codegen", - "libc", - "target-lexicon", -] - -[[package]] -name = "cranelift-wasm" -version = "0.95.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff3220489a3d928ad91e59dd7aeaa8b3de18afb554a6211213673a71c90737ac" -dependencies = [ - "cranelift-codegen", - "cranelift-entity", - "cranelift-frontend", - "itertools 0.10.5", - "log", - "smallvec", - "wasmparser", - "wasmtime-types", -] - -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" +name = "crossbeam-channel" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ - "cfg-if", + "crossbeam-utils", ] [[package]] @@ -1485,9 +1324,9 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -1497,29 +1336,19 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array 0.12.4", - "subtle 1.0.0", -] - [[package]] name = "crypto-mac" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.7", - "subtle 2.6.1", + "generic-array", + "subtle", ] [[package]] @@ -1528,20 +1357,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.4.4", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle 2.6.1", - "zeroize", + "cipher", ] [[package]] @@ -1556,7 +1372,7 @@ dependencies = [ "digest 0.10.7", "fiat-crypto", "rustc_version 0.4.1", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -1571,63 +1387,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "cxx" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c042a0ba58aaff55299632834d1ea53ceff73d62373f62c9ae60890ad1b942" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dc1c88d0fdac57518a9b1f6c4f4fb2aca8f3c30c0d03d7d8518b47ca0bcea6" -dependencies = [ - "cc", - "codespan-reporting", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.89", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7ed7d30b289e2592cc55bc2ccd89803a63c913e008e6eb59f06cddf45bb52f" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c465d22de46b851c04630a5fc749a26005b263632ed2e0d9cc81518ead78d" -dependencies = [ - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.89", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core 0.9.10", -] - [[package]] name = "data-encoding" version = "2.6.0" @@ -1666,9 +1425,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs", "displaydoc", @@ -1709,19 +1468,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 2.0.89", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -1748,28 +1494,13 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -1781,49 +1512,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.6.1", -] - -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "directories-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", + "subtle", ] [[package]] @@ -1897,16 +1586,10 @@ dependencies = [ "regex", "syn 2.0.89", "termcolor", - "toml 0.8.19", + "toml", "walkdir", ] -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - [[package]] name = "dtoa" version = "1.0.9" @@ -1951,19 +1634,10 @@ dependencies = [ "elliptic-curve", "rfc6979", "serdect", - "signature 2.2.0", + "signature", "spki", ] -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature 1.6.4", -] - [[package]] name = "ed25519" version = "2.2.3" @@ -1971,35 +1645,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature 2.2.0", + "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek 3.2.0", - "ed25519 1.5.3", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", - "rand_core 0.6.4", + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", "serde", "sha2 0.10.8", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -2009,8 +1669,8 @@ version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", + "curve25519-dalek", + "ed25519", "hashbrown 0.14.5", "hex", "rand_core 0.6.4", @@ -2034,34 +1694,16 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array 0.14.7", + "generic-array", "group", "pkcs8", "rand_core 0.6.4", "sec1", "serdect", - "subtle 2.6.1", + "subtle", "zeroize", ] -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "enum-as-inner" version = "0.6.1" @@ -2109,34 +1751,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "etf-crypto-primitives" -version = "0.2.4" -source = "git+https://github.com/ideal-lab5/etf-sdk?branch=jg/debug#41936cb490738b536d66cbf82b9713f6f87d434a" -dependencies = [ - "aes-gcm", - "ark-bls12-377", - "ark-bls12-381", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "array-bytes 6.2.3", - "chacha20poly1305", - "generic-array 0.14.7", - "log", - "parity-scale-codec", - "rand_chacha 0.3.1", - "scale-info", - "serde", - "serde_cbor", - "serde_json", - "sha2 0.10.8", - "sha3", - "w3f-bls", -] - [[package]] name = "etf-crypto-primitives" version = "0.2.4" @@ -2152,7 +1766,7 @@ dependencies = [ "ark-std", "array-bytes 6.2.3", "chacha20poly1305", - "generic-array 0.14.7", + "generic-array", "parity-scale-codec", "rand_chacha 0.3.1", "scale-info", @@ -2179,7 +1793,7 @@ dependencies = [ "ark-std", "array-bytes 6.2.3", "chacha20poly1305", - "generic-array 0.14.7", + "generic-array", "parity-scale-codec", "rand_chacha 0.3.1", "scale-info", @@ -2205,7 +1819,7 @@ checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.15", + "pin-project-lite", ] [[package]] @@ -2215,16 +1829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", - "pin-project-lite 0.2.15", -] - -[[package]] -name = "exit-future" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" -dependencies = [ - "futures", + "pin-project-lite", ] [[package]] @@ -2233,26 +1838,23 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2c470c71d91ecbd179935b24170459e926382eaaa86b590b78814e180d8a8e2" dependencies = [ - "blake2 0.10.6", + "blake2", "file-guard", "fs-err", - "prettyplease 0.2.25", + "prettyplease", "proc-macro2", "quote", "syn 2.0.89", ] [[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-iterator" -version = "0.3.0" +name = "fastrand" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] name = "fastrand" @@ -2267,7 +1869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -2299,44 +1901,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "file-per-thread-logger" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" -dependencies = [ - "env_logger", - "log", -] - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "finality-grandpa" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36530797b9bf31cd4ff126dcfee8170f86b00cfdcea3269d73133cc0415945c3" -dependencies = [ - "either", - "futures", - "futures-timer", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot 0.12.3", - "scale-info", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2355,26 +1919,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "libz-sys", - "miniz_oxide", -] - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2382,27 +1926,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "foldhash" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "fork-tree" -version = "12.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", -] +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "form_urlencoded" @@ -2413,22 +1940,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "forwarded-header-value" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" -dependencies = [ - "nonempty", - "thiserror", -] - -[[package]] -name = "fragile" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" - [[package]] name = "frame-benchmarking" version = "28.0.0" @@ -2484,7 +1995,7 @@ name = "frame-election-provider-solution-type" version = "13.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -2515,7 +2026,6 @@ dependencies = [ "aquamarine", "frame-support 28.0.0", "frame-system 28.0.0", - "frame-try-runtime", "log", "parity-scale-codec", "scale-info", @@ -2538,32 +2048,6 @@ dependencies = [ "serde", ] -[[package]] -name = "frame-metadata" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daaf440c68eb2c3d88e5760fe8c7af3f9fee9181fab6c2f2c4e7cc48dcc40bb8" -dependencies = [ - "cfg-if", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "frame-metadata-hash-extension" -version = "0.1.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "docify", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-runtime 31.0.1", -] - [[package]] name = "frame-support" version = "28.0.0" @@ -2574,7 +2058,7 @@ dependencies = [ "bitflags 1.3.2", "docify", "environmental", - "frame-metadata 16.0.0", + "frame-metadata", "frame-support-procedural 23.0.0", "impl-trait-for-tuples", "k256", @@ -2616,7 +2100,7 @@ dependencies = [ "bitflags 1.3.2", "docify", "environmental", - "frame-metadata 16.0.0", + "frame-metadata", "frame-support-procedural 30.0.4", "impl-trait-for-tuples", "k256", @@ -2692,7 +2176,7 @@ version = "10.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "frame-support-procedural-tools-derive 11.0.0", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -2705,7 +2189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81a088fd6fda5f53ff0c17fc7551ce8bd0ead14ba742228443c8196296a7369b" dependencies = [ "frame-support-procedural-tools-derive 12.0.0", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -2739,7 +2223,7 @@ source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1 dependencies = [ "frame-benchmarking 28.0.0", "frame-executive", - "frame-metadata 16.0.0", + "frame-metadata", "frame-support 28.0.0", "frame-support-test-pallet", "frame-system 28.0.0", @@ -2814,28 +2298,6 @@ dependencies = [ "sp-weights 31.0.0", ] -[[package]] -name = "frame-system-rpc-runtime-api" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "parity-scale-codec", - "sp-api 26.0.0", -] - -[[package]] -name = "frame-try-runtime" -version = "0.34.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "parity-scale-codec", - "sp-api 26.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "fs-err" version = "2.11.0" @@ -2845,16 +2307,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "funty" version = "2.0.0" @@ -2910,14 +2362,32 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-lite" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ + "fastrand 2.2.0", "futures-core", - "pin-project-lite 0.2.15", + "futures-io", + "parking", + "pin-project-lite", ] [[package]] @@ -2933,13 +2403,13 @@ dependencies = [ [[package]] name = "futures-rustls" -version = "0.22.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.20.9", - "webpki", + "rustls", + "rustls-pki-types", ] [[package]] @@ -2973,27 +2443,22 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.15", + "pin-project-lite", "pin-utils", "slab", ] [[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.12.4" +name = "generator" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" dependencies = [ - "typenum", + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", ] [[package]] @@ -3009,26 +2474,27 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", - "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -3047,31 +2513,10 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.1", + "opaque-debug", "polyval", ] -[[package]] -name = "gimli" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -dependencies = [ - "fallible-iterator 0.2.0", - "indexmap 1.9.3", - "stable_deref_trait", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -dependencies = [ - "fallible-iterator 0.3.0", - "stable_deref_trait", -] - [[package]] name = "gimli" version = "0.31.1" @@ -3085,23 +2530,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "governor" -version = "0.6.3" +name = "gloo-timers" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ - "cfg-if", - "dashmap", - "futures", - "futures-timer", - "no-std-compat", - "nonzero_ext", - "parking_lot 0.12.3", - "portable-atomic", - "quanta", - "rand 0.8.5", - "smallvec", - "spinning_top", + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -3112,22 +2549,22 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", ] [[package]] name = "h2" -version = "0.3.26" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap", "slab", "tokio", "tokio-util", @@ -3155,12 +2592,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.2" @@ -3185,12 +2616,17 @@ name = "hashbrown" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -3235,10 +2671,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] -name = "hex-literal" -version = "0.4.1" +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d00147af6310f4392a31680db52a3ed45a2e0f68eb18e8c3fe5537ecc96d9e2" +dependencies = [ + "async-recursion", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.0", + "socket2 0.5.7", + "thiserror 2.0.11", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "5762f69ebdbd4ddb2e975cd24690bf21fe6b2604039189c26acddbc427f12887" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.0", + "resolv-conf", + "smallvec", + "thiserror 2.0.11", + "tokio", + "tracing", +] [[package]] name = "hkdf" @@ -3255,7 +2738,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac", "digest 0.9.0", ] @@ -3275,19 +2758,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.7", + "generic-array", "hmac 0.8.1", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -3310,22 +2784,39 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", - "pin-project-lite 0.2.15", + "http 1.2.0", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http-body-util" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body", + "pin-project-lite", +] [[package]] name = "httparse" @@ -3333,12 +2824,6 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "humantime" version = "2.1.0" @@ -3347,65 +2832,41 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.31" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", - "http", + "http 1.2.0", "http-body", "httparse", - "httpdate", "itoa", - "pin-project-lite 0.2.15", - "socket2 0.5.7", + "pin-project-lite", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] -name = "hyper-rustls" -version = "0.24.2" +name = "hyper-util" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ + "bytes", + "futures-channel", "futures-util", - "http", + "http 1.2.0", + "http-body", "hyper", - "log", - "rustls 0.21.12", - "rustls-native-certs", + "pin-project-lite", + "socket2 0.5.7", "tokio", - "tokio-rustls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", + "tower-service", + "tracing", ] [[package]] @@ -3526,27 +2987,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.0.3" @@ -3584,7 +3024,7 @@ version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" dependencies = [ - "async-io", + "async-io 2.4.0", "core-foundation", "fnv", "futures", @@ -3596,9 +3036,31 @@ dependencies = [ "netlink-proto", "netlink-sys", "rtnetlink", + "smol", "system-configuration", "tokio", - "windows", + "windows 0.53.0", +] + +[[package]] +name = "igd-next" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b0d7d4541def58a37bf8efc559683f21edce7c82f0d866c93ac21f7e098f93" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http 1.2.0", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.8.5", + "tokio", + "url", + "xmltree", ] [[package]] @@ -3678,17 +3140,6 @@ dependencies = [ "quote", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - [[package]] name = "indexmap" version = "2.6.0" @@ -3705,7 +3156,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -3737,12 +3188,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "ip_network" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" - [[package]] name = "ipconfig" version = "0.3.2" @@ -3805,15 +3250,6 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.72" @@ -3823,92 +3259,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonrpsee" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" -dependencies = [ - "jsonrpsee-core", - "jsonrpsee-proc-macros", - "jsonrpsee-server", - "jsonrpsee-types", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-util", - "hyper", - "jsonrpsee-types", - "parking_lot 0.12.3", - "rand 0.8.5", - "rustc-hash", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "jsonrpsee-server" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d8b6a9674422a8572e0b0abb12feeb3f2aeda86528c80d0350c2bd0923ab41" -dependencies = [ - "futures-util", - "http", - "hyper", - "jsonrpsee-core", - "jsonrpsee-types", - "pin-project", - "route-recognizer", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tracing", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "k256" version = "0.13.4" @@ -3933,28 +3283,12 @@ dependencies = [ ] [[package]] -name = "keystream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" - -[[package]] -name = "kvdb" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" -dependencies = [ - "smallvec", -] - -[[package]] -name = "kvdb-memorydb" -version = "0.13.0" +name = "kv-log-macro" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ - "kvdb", - "parking_lot 0.12.3", + "log", ] [[package]] @@ -3965,418 +3299,366 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.164" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" - -[[package]] -name = "libm" -version = "0.2.11" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libp2p" -version = "0.51.4" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f35eae38201a993ece6bdc823292d6abd1bffed1c4d0f4a3517d2bd8e1d917fe" +checksum = "b72dc443ddd0254cb49a794ed6b6728400ee446a0f7ab4a07d0209ee98de20e9" dependencies = [ "bytes", + "either", "futures", "futures-timer", "getrandom 0.2.15", - "instant", "libp2p-allow-block-list", "libp2p-connection-limits", "libp2p-core", "libp2p-dns", - "libp2p-identify", + "libp2p-gossipsub", "libp2p-identity", - "libp2p-kad", "libp2p-mdns", "libp2p-metrics", "libp2p-noise", "libp2p-ping", "libp2p-quic", - "libp2p-request-response", "libp2p-swarm", "libp2p-tcp", - "libp2p-wasm-ext", + "libp2p-upnp", "libp2p-websocket", "libp2p-yamux", "multiaddr", "pin-project", + "rw-stream-sink", + "thiserror 2.0.11", ] [[package]] name = "libp2p-allow-block-list" -version = "0.1.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510daa05efbc25184458db837f6f9a5143888f1caa742426d92e1833ddd38a50" +checksum = "38944b7cb981cc93f2f0fb411ff82d0e983bd226fbcc8d559639a3a73236568b" dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "void", ] [[package]] name = "libp2p-connection-limits" -version = "0.1.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caa33f1d26ed664c4fe2cca81a08c8e07d4c1c04f2f4ac7655c2dd85467fda0" +checksum = "efe9323175a17caa8a2ed4feaf8a548eeef5e0b72d03840a0eab4bcb0210ce1c" dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "void", ] [[package]] name = "libp2p-core" -version = "0.39.2" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1df63c0b582aa434fb09b2d86897fa2b419ffeccf934b36f87fcedc8e835c2" +checksum = "193c75710ba43f7504ad8f58a62ca0615b1d7e572cb0f1780bc607252c39e9ef" dependencies = [ "either", "fnv", "futures", "futures-timer", - "instant", "libp2p-identity", - "log", "multiaddr", - "multihash 0.17.0", + "multihash", "multistream-select", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "quick-protobuf", "rand 0.8.5", "rw-stream-sink", - "smallvec", - "thiserror", - "unsigned-varint", - "void", + "thiserror 2.0.11", + "tracing", + "unsigned-varint 0.8.0", + "web-time", ] [[package]] name = "libp2p-dns" -version = "0.39.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146ff7034daae62077c415c2376b8057368042df6ab95f5432ad5e88568b1554" +checksum = "1b780a1150214155b0ed1cdf09fbd2e1b0442604f9146a431d1b21d23eef7bd7" dependencies = [ + "async-std-resolver", + "async-trait", "futures", + "hickory-resolver", "libp2p-core", - "log", - "parking_lot 0.12.3", + "libp2p-identity", + "parking_lot", "smallvec", - "trust-dns-resolver 0.22.0", + "tracing", ] [[package]] -name = "libp2p-identify" -version = "0.42.2" +name = "libp2p-gossipsub" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5455f472243e63b9c497ff320ded0314254a9eb751799a39c283c6f20b793f3c" +checksum = "d558548fa3b5a8e9b66392f785921e363c57c05dcadfda4db0d41ae82d313e4a" dependencies = [ + "async-channel 2.3.1", "asynchronous-codec", + "base64 0.22.1", + "byteorder", + "bytes", "either", + "fnv", "futures", "futures-timer", + "getrandom 0.2.15", + "hashlink", + "hex_fmt", "libp2p-core", "libp2p-identity", "libp2p-swarm", - "log", - "lru", + "prometheus-client", "quick-protobuf", "quick-protobuf-codec", - "smallvec", - "thiserror", - "void", + "rand 0.8.5", + "regex", + "sha2 0.10.8", + "tracing", + "web-time", ] [[package]] name = "libp2p-identity" -version = "0.1.3" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce" +checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" dependencies = [ - "bs58 0.4.0", - "ed25519-dalek 2.1.1", - "log", - "multiaddr", - "multihash 0.17.0", + "bs58", + "ed25519-dalek", + "hkdf", + "multihash", "quick-protobuf", "rand 0.8.5", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", + "tracing", "zeroize", ] -[[package]] -name = "libp2p-kad" -version = "0.43.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d5ef876a2b2323d63c258e63c2f8e36f205fe5a11f0b3095d59635650790ff" -dependencies = [ - "arrayvec", - "asynchronous-codec", - "bytes", - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "log", - "quick-protobuf", - "rand 0.8.5", - "sha2 0.10.8", - "smallvec", - "thiserror", - "uint 0.9.5", - "unsigned-varint", - "void", -] - [[package]] name = "libp2p-mdns" -version = "0.43.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19983e1f949f979a928f2c603de1cf180cc0dc23e4ac93a62651ccb18341460b" +checksum = "11d0ba095e1175d797540e16b62e7576846b883cb5046d4159086837b36846cc" dependencies = [ - "data-encoding", + "async-io 2.4.0", + "async-std", "futures", + "hickory-proto", "if-watch", "libp2p-core", "libp2p-identity", "libp2p-swarm", - "log", "rand 0.8.5", "smallvec", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", - "trust-dns-proto 0.22.0", - "void", + "tracing", ] [[package]] name = "libp2p-metrics" -version = "0.12.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42ec91e227d7d0dafa4ce88b333cdf5f277253873ab087555c92798db2ddd46" +checksum = "2ce58c64292e87af624fcb86465e7dd8342e46a388d71e8fec0ab37ee789630a" dependencies = [ + "futures", "libp2p-core", - "libp2p-identify", - "libp2p-kad", + "libp2p-gossipsub", + "libp2p-identity", "libp2p-ping", "libp2p-swarm", + "pin-project", "prometheus-client", + "web-time", ] [[package]] name = "libp2p-noise" -version = "0.42.2" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3673da89d29936bc6435bafc638e2f184180d554ce844db65915113f86ec5e" +checksum = "afcc133e0f3cea07acde6eb8a9665cb11b600bd61110b010593a0210b8153b16" dependencies = [ + "asynchronous-codec", "bytes", - "curve25519-dalek 3.2.0", "futures", "libp2p-core", "libp2p-identity", - "log", + "multiaddr", + "multihash", "once_cell", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", "snow", "static_assertions", - "thiserror", - "x25519-dalek 1.1.1", + "thiserror 2.0.11", + "tracing", + "x25519-dalek", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.42.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e57759c19c28a73ef1eb3585ca410cefb72c1a709fcf6de1612a378e4219202" +checksum = "7b2529993ff22deb2504c0130a58b60fb77f036be555053922db1a0490b5798b" dependencies = [ - "either", "futures", "futures-timer", - "instant", "libp2p-core", + "libp2p-identity", "libp2p-swarm", - "log", "rand 0.8.5", - "void", + "tracing", + "web-time", ] [[package]] name = "libp2p-quic" -version = "0.7.0-alpha.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b26abd81cd2398382a1edfe739b539775be8a90fa6914f39b2ab49571ec735" +checksum = "41432a159b00424a0abaa2c80d786cddff81055ac24aa127e0cf375f7858d880" dependencies = [ - "bytes", + "async-std", "futures", "futures-timer", "if-watch", "libp2p-core", "libp2p-identity", "libp2p-tls", - "log", - "parking_lot 0.12.3", - "quinn-proto", + "quinn", "rand 0.8.5", - "rustls 0.20.9", - "thiserror", + "ring 0.17.8", + "rustls", + "socket2 0.5.7", + "thiserror 2.0.11", "tokio", -] - -[[package]] -name = "libp2p-request-response" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffdb374267d42dc5ed5bc53f6e601d4a64ac5964779c6e40bb9e4f14c1e30d5" -dependencies = [ - "async-trait", - "futures", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "rand 0.8.5", - "smallvec", + "tracing", ] [[package]] name = "libp2p-swarm" -version = "0.42.2" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903b3d592d7694e56204d211f29d31bc004be99386644ba8731fc3e3ef27b296" +checksum = "803399b4b6f68adb85e63ab573ac568154b193e9a640f03e0f2890eabbcb37f8" dependencies = [ + "async-std", "either", "fnv", "futures", "futures-timer", - "instant", "libp2p-core", "libp2p-identity", - "libp2p-swarm-derive", - "log", + "lru", + "multistream-select", + "once_cell", "rand 0.8.5", "smallvec", "tokio", - "void", -] - -[[package]] -name = "libp2p-swarm-derive" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" -dependencies = [ - "heck 0.4.1", - "quote", - "syn 1.0.109", + "tracing", + "web-time", ] [[package]] name = "libp2p-tcp" -version = "0.39.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d33698596d7722d85d3ab0c86c2c322254fce1241e91208e3679b4eb3026cf" +checksum = "65346fb4d36035b23fec4e7be4c320436ba53537ce9b6be1d1db1f70c905cad0" dependencies = [ + "async-io 2.4.0", "futures", "futures-timer", "if-watch", "libc", "libp2p-core", - "log", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", + "tracing", ] [[package]] name = "libp2p-tls" -version = "0.1.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" +checksum = "dcaebc1069dea12c5b86a597eaaddae0317c2c2cb9ec99dc94f82fd340f5c78b" dependencies = [ "futures", "futures-rustls", "libp2p-core", "libp2p-identity", "rcgen", - "ring 0.16.20", - "rustls 0.20.9", - "thiserror", - "webpki", - "x509-parser 0.14.0", + "ring 0.17.8", + "rustls", + "rustls-webpki 0.101.7", + "thiserror 2.0.11", + "x509-parser", "yasna", ] [[package]] -name = "libp2p-wasm-ext" -version = "0.39.0" +name = "libp2p-upnp" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77dff9d32353a5887adb86c8afc1de1a94d9e8c3bc6df8b2201d7cdf5c848f43" +checksum = "d457b9ecceb66e7199f049926fad447f1f17f040e8d29d690c086b4cab8ed14a" dependencies = [ "futures", - "js-sys", + "futures-timer", + "igd-next", "libp2p-core", - "parity-send-wrapper", - "wasm-bindgen", - "wasm-bindgen-futures", + "libp2p-swarm", + "tokio", + "tracing", ] [[package]] name = "libp2p-websocket" -version = "0.41.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111273f7b3d3510524c752e8b7a5314b7f7a1fee7e68161c01a7d72cbb06db9f" +checksum = "2bf5d48a4d8fad8a49fbf23816a878cac25623549f415d74da8ef4327e6196a9" dependencies = [ "either", "futures", "futures-rustls", "libp2p-core", - "log", - "parking_lot 0.12.3", - "quicksink", + "libp2p-identity", + "parking_lot", + "pin-project-lite", "rw-stream-sink", "soketto", + "thiserror 2.0.11", + "tracing", "url", "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.43.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd21d950662700a385d4c6d68e2f5f54d778e97068cdd718522222ef513bda" +checksum = "f15df094914eb4af272acf9adaa9e287baa269943f32ea348ba29cfb9bfc60d8" dependencies = [ + "either", "futures", "libp2p-core", - "log", - "thiserror", - "yamux", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall 0.5.7", + "thiserror 2.0.11", + "tracing", + "yamux 0.12.1", + "yamux 0.13.4", ] [[package]] @@ -4406,7 +3688,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -4427,41 +3709,6 @@ dependencies = [ "libsecp256k1-core", ] -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" -dependencies = [ - "cc", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linked_hash_set" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "linregress" version = "0.5.4" @@ -4473,9 +3720,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" @@ -4483,79 +3730,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "lioness" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9" -dependencies = [ - "arrayref", - "blake2 0.8.1", - "chacha", - "keystream", -] - [[package]] name = "litemap" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" -[[package]] -name = "litep2p" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f02542ae3a94b4c4ffa37dc56388c923e286afa3bf65452e3984b50b2a2f316" -dependencies = [ - "async-trait", - "bs58 0.4.0", - "bytes", - "cid 0.10.1", - "ed25519-dalek 1.0.1", - "futures", - "futures-timer", - "hex-literal", - "indexmap 2.6.0", - "libc", - "mockall 0.12.1", - "multiaddr", - "multihash 0.17.0", - "network-interface", - "nohash-hasher", - "parking_lot 0.12.3", - "pin-project", - "prost 0.11.9", - "prost-build 0.11.9", - "quinn", - "rand 0.8.5", - "rcgen", - "ring 0.16.20", - "rustls 0.20.9", - "serde", - "sha2 0.10.8", - "simple-dns", - "smallvec", - "snow", - "socket2 0.5.7", - "static_assertions", - "str0m", - "thiserror", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tracing", - "trust-dns-resolver 0.23.2", - "uint 0.9.5", - "unsigned-varint", - "url", - "webpki", - "x25519-dalek 2.0.1", - "x509-parser 0.15.1", - "yasna", - "zeroize", -] - [[package]] name = "lock_api" version = "0.4.12" @@ -4571,51 +3751,30 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lru" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" -dependencies = [ - "hashbrown 0.13.2", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "lz4" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" dependencies = [ - "lz4-sys", + "value-bag", ] [[package]] -name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" +name = "loom" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ - "cc", - "libc", + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber 0.3.18", ] [[package]] -name = "mach" -version = "0.3.2" +name = "lru" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "libc", + "hashbrown 0.15.1", ] [[package]] @@ -4681,12 +3840,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matrixmultiply" version = "0.3.9" @@ -4703,42 +3856,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memfd" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" -dependencies = [ - "rustix 0.38.41", -] - -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - -[[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.32.0" @@ -4748,20 +3865,6 @@ dependencies = [ "hash-db", ] -[[package]] -name = "merkleized-metadata" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943f6d92804ed0100803d51fa9b21fd9432b5d122ba4c713dc26fe6d2f619cf6" -dependencies = [ - "array-bytes 6.2.3", - "blake3", - "frame-metadata 18.0.0", - "parity-scale-codec", - "scale-decode", - "scale-info", -] - [[package]] name = "merlin" version = "3.0.0" @@ -4802,100 +3905,40 @@ dependencies = [ ] [[package]] -name = "mixnet" -version = "0.7.0" +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "loom", + "parking_lot", + "portable-atomic", + "rustc_version 0.4.1", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "multiaddr" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" -dependencies = [ - "arrayref", - "arrayvec", - "bitflags 1.3.2", - "blake2 0.10.6", - "c2-chacha", - "curve25519-dalek 4.1.3", - "either", - "hashlink", - "lioness", - "log", - "parking_lot 0.12.3", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_distr", - "subtle 2.6.1", - "thiserror", - "zeroize", -] - -[[package]] -name = "mockall" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive 0.11.4", - "predicates 2.1.5", - "predicates-tree", -] - -[[package]] -name = "mockall" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive 0.12.1", - "predicates 3.1.2", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "mockall_derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "multiaddr" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b36f567c7099511fa8612bbbb52dda2419ce0bdbacf31714e3a5ffdb766d3bd" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", "data-encoding", - "log", + "libp2p-identity", "multibase", - "multihash 0.17.0", + "multihash", "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", ] @@ -4912,58 +3955,14 @@ dependencies = [ [[package]] name = "multihash" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" -dependencies = [ - "blake2b_simd", - "blake2s_simd", - "blake3", - "core2", - "digest 0.10.7", - "multihash-derive", - "sha2 0.10.8", - "sha3", - "unsigned-varint", -] - -[[package]] -name = "multihash" -version = "0.18.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd8a792c1694c6da4f68db0a9d707c72bd260994da179e6030a5dcee00bb815" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ - "blake2b_simd", - "blake2s_simd", - "blake3", "core2", - "digest 0.10.7", - "multihash-derive", - "sha2 0.10.8", - "sha3", - "unsigned-varint", -] - -[[package]] -name = "multihash-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "unsigned-varint 0.8.0", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "multimap" version = "0.10.0" @@ -4972,16 +3971,16 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "multistream-select" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" dependencies = [ "bytes", "futures", "log", "pin-project", "smallvec", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] @@ -5069,7 +4068,7 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -5083,7 +4082,7 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -5093,6 +4092,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ + "async-io 1.13.0", "bytes", "futures", "libc", @@ -5100,18 +4100,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "network-interface" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" -dependencies = [ - "cc", - "libc", - "thiserror", - "winapi", -] - [[package]] name = "nix" version = "0.26.4" @@ -5123,12 +4111,6 @@ dependencies = [ "libc", ] -[[package]] -name = "no-std-compat" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -5145,24 +4127,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nonempty" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" - -[[package]] -name = "nonzero_ext" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -5235,7 +4199,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -5248,27 +4211,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.30.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" -dependencies = [ - "crc32fast", - "hashbrown 0.13.2", - "indexmap 1.9.3", - "memchr", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.36.5" @@ -5280,9 +4222,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] @@ -5293,78 +4235,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.4.1+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - [[package]] name = "overload" version = "0.1.1" @@ -5385,30 +4261,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "pallet-babe" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-authorship", - "pallet-session", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "sp-application-crypto 30.0.0", - "sp-consensus-babe", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-staking 26.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "pallet-balances" version = "28.0.0" @@ -5509,7 +4361,7 @@ dependencies = [ "sp-ark-bls12-381", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-keyring 39.0.0", + "sp-keyring", "sp-keystore 0.40.0", "sp-runtime 39.0.5", "timelock 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5805,7 +4657,7 @@ name = "pallet-staking-reward-curve" version = "11.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -5854,33 +4706,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ "bitcoin_hashes", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] -[[package]] -name = "parity-db" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" -dependencies = [ - "blake2 0.10.6", - "crc32fast", - "fs2", - "hex", - "libc", - "log", - "lz4", - "memmap2 0.5.10", - "parking_lot 0.12.3", - "rand 0.8.5", - "siphasher", - "snap", - "winapi", -] - [[package]] name = "parity-scale-codec" version = "3.7.0" @@ -5903,18 +4734,12 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" - [[package]] name = "parity-wasm" version = "0.45.0" @@ -5927,17 +4752,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -5945,21 +4759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -5970,17 +4770,11 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] -[[package]] -name = "partial_sort" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" - [[package]] name = "password-hash" version = "0.5.0" @@ -5989,7 +4783,7 @@ checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -6010,11 +4804,12 @@ dependencies = [ [[package]] name = "pem" -version = "1.1.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", + "serde", ] [[package]] @@ -6030,7 +4825,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap", ] [[package]] @@ -6053,12 +4848,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.15" @@ -6071,6 +4860,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.2.0", + "futures-io", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -6081,12 +4881,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - [[package]] name = "polkadot-ckb-merkle-mountain-range" version = "0.7.0" @@ -6098,35 +4892,10 @@ dependencies = [ ] [[package]] -name = "polkavm" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3693e5efdb2bf74e449cd25fd777a28bd7ed87e41f5d5da75eb31b4de48b94" -dependencies = [ - "libc", - "log", - "polkavm-assembler", - "polkavm-common", - "polkavm-linux-raw", -] - -[[package]] -name = "polkavm-assembler" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa96d6d868243acc12de813dd48e756cbadcc8e13964c70d272753266deadc1" -dependencies = [ - "log", -] - -[[package]] -name = "polkavm-common" -version = "0.9.0" +name = "polkavm-common" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" -dependencies = [ - "log", -] [[package]] name = "polkavm-derive" @@ -6160,26 +4929,21 @@ dependencies = [ ] [[package]] -name = "polkavm-linker" -version = "0.9.2" +name = "polling" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ - "gimli 0.28.1", - "hashbrown 0.14.5", + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", "log", - "object 0.32.2", - "polkavm-common", - "regalloc2 0.9.3", - "rustc-demangle", + "pin-project-lite", + "windows-sys 0.48.0", ] -[[package]] -name = "polkavm-linux-raw" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" - [[package]] name = "polling" version = "3.7.4" @@ -6189,7 +4953,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", - "pin-project-lite 0.2.15", + "pin-project-lite", "rustix 0.38.41", "tracing", "windows-sys 0.59.0", @@ -6202,7 +4966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug", "universal-hash", ] @@ -6214,7 +4978,7 @@ checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug", "universal-hash", ] @@ -6236,47 +5000,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", -] - -[[package]] -name = "predicates" -version = "2.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" -dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", - "predicates-core", - "regex", -] - -[[package]] -name = "predicates" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" -dependencies = [ - "anstyle", - "predicates-core", -] - -[[package]] -name = "predicates-core" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" - -[[package]] -name = "predicates-tree" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" -dependencies = [ - "predicates-core", - "termtree", + "zerocopy 0.7.35", ] [[package]] @@ -6289,16 +5013,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.25" @@ -6334,16 +5048,6 @@ dependencies = [ "uint 0.10.0", ] -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" -dependencies = [ - "thiserror", - "toml 0.5.11", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -6397,29 +5101,15 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prometheus" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" -dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "memchr", - "parking_lot 0.12.3", - "thiserror", -] - [[package]] name = "prometheus-client" -version = "0.19.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6fa99d535dd930d1249e6c79cb3c2915f9172a540fe2b02a4c8f9ca954721e" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot", "prometheus-client-derive-encode", ] @@ -6436,62 +5126,29 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive 0.12.6", -] - -[[package]] -name = "prost-build" -version = "0.11.9" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap 0.8.3", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.12.6" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" dependencies = [ - "bytes", "heck 0.5.0", "itertools 0.12.1", "log", - "multimap 0.10.0", + "multimap", "once_cell", "petgraph", - "prettyplease 0.2.25", - "prost 0.12.6", - "prost-types 0.12.6", + "prettyplease", + "prost", + "prost-types", "regex", "syn 2.0.89", "tempfile", @@ -6499,22 +5156,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", "itertools 0.12.1", @@ -6525,44 +5169,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost 0.12.6", -] - -[[package]] -name = "psm" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" -dependencies = [ - "cc", -] - -[[package]] -name = "quanta" -version = "0.12.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" dependencies = [ - "crossbeam-utils", - "libc", - "once_cell", - "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", - "web-sys", - "winapi", + "prost", ] [[package]] @@ -6582,75 +5193,70 @@ dependencies = [ [[package]] name = "quick-protobuf-codec" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1693116345026436eb2f10b677806169c1a1260c1c60eaaffe3fb5a29ae23d8b" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" dependencies = [ "asynchronous-codec", "bytes", "quick-protobuf", - "thiserror", - "unsigned-varint", -] - -[[package]] -name = "quicksink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" -dependencies = [ - "futures-core", - "futures-sink", - "pin-project-lite 0.1.12", + "thiserror 1.0.69", + "unsigned-varint 0.8.0", ] [[package]] name = "quinn" -version = "0.9.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ + "async-io 2.4.0", + "async-std", "bytes", - "pin-project-lite 0.2.15", + "futures-io", + "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.20.9", - "thiserror", + "rustls", + "socket2 0.5.7", + "thiserror 2.0.11", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.9.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.15", "rand 0.8.5", - "ring 0.16.20", + "ring 0.17.8", "rustc-hash", - "rustls 0.20.9", + "rustls", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.11", "tinyvec", "tracing", - "webpki", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.3.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ + "cfg_aliases", "libc", - "quinn-proto", - "socket2 0.4.10", + "once_cell", + "socket2 0.5.7", "tracing", - "windows-sys 0.42.0", + "windows-sys 0.59.0", ] [[package]] @@ -6668,19 +5274,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -6693,13 +5286,14 @@ dependencies = [ ] [[package]] -name = "rand_chacha" -version = "0.2.2" +name = "rand" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.17", ] [[package]] @@ -6713,12 +5307,13 @@ dependencies = [ ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ - "getrandom 0.1.16", + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -6731,40 +5326,13 @@ dependencies = [ ] [[package]] -name = "rand_distr" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "raw-cpuid" -version = "11.2.0" +name = "rand_core" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" dependencies = [ - "bitflags 2.6.0", + "getrandom 0.3.1", + "zerocopy 0.8.17", ] [[package]] @@ -6795,9 +5363,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" dependencies = [ "pem", "ring 0.16.20", @@ -6805,15 +5373,6 @@ dependencies = [ "yasna", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.7" @@ -6823,17 +5382,6 @@ dependencies = [ "bitflags 2.6.0", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror", -] - [[package]] name = "ref-cast" version = "1.0.23" @@ -6854,31 +5402,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "regalloc2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621" -dependencies = [ - "fxhash", - "log", - "slice-group-by", - "smallvec", -] - -[[package]] -name = "regalloc2" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" -dependencies = [ - "hashbrown 0.13.2", - "log", - "rustc-hash", - "slice-group-by", - "smallvec", -] - [[package]] name = "regex" version = "1.11.1" @@ -6940,7 +5463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -6955,7 +5478,7 @@ dependencies = [ "ark-std", "ark-transcript 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec", - "blake2 0.10.6", + "blake2", "common", "fflonk", ] @@ -6990,18 +5513,13 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "route-recognizer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" - [[package]] name = "rtnetlink" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" dependencies = [ + "async-global-executor", "futures", "log", "netlink-packet-core", @@ -7010,7 +5528,7 @@ dependencies = [ "netlink-proto", "netlink-sys", "nix", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -7022,9 +5540,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -7061,16 +5579,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.17" +version = "0.37.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", ] [[package]] @@ -7088,47 +5606,25 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.9" +version = "0.23.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", + "once_cell", "ring 0.17.8", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-pki-types" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" dependencies = [ - "base64 0.21.7", + "web-time", ] [[package]] @@ -7142,963 +5638,80 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "rw-stream-sink" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" -dependencies = [ - "futures", - "pin-project", - "static_assertions", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "safe-mix" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c" -dependencies = [ - "rustc_version 0.2.3", -] - -[[package]] -name = "safe_arch" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "sc-allocator" -version = "23.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "log", - "sp-core 28.0.0", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror", -] - -[[package]] -name = "sc-block-builder" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "sp-api 26.0.0", - "sp-block-builder", - "sp-blockchain", - "sp-core 28.0.0", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "sp-trie 29.0.0", -] - -[[package]] -name = "sc-chain-spec" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "docify", - "log", - "memmap2 0.9.5", - "parity-scale-codec", - "sc-chain-spec-derive", - "sc-client-api", - "sc-executor", - "sc-network", - "sc-telemetry", - "serde", - "serde_json", - "sp-blockchain", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-genesis-builder 0.8.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "sc-chain-spec-derive" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "sc-client-api" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "fnv", - "futures", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-executor", - "sc-transaction-pool-api", - "sc-utils", - "sp-api 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-database", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "sp-statement-store", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-trie 29.0.0", - "substrate-prometheus-endpoint", -] - -[[package]] -name = "sc-client-db" -version = "0.35.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hash-db", - "kvdb", - "kvdb-memorydb", - "linked-hash-map", - "log", - "parity-db", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-client-api", - "sc-state-db", - "schnellru", - "sp-arithmetic 23.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-database", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "sp-trie 29.0.0", -] - -[[package]] -name = "sc-consensus" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "futures", - "log", - "mockall 0.11.4", - "parking_lot 0.12.3", - "sc-client-api", - "sc-network-types", - "sc-utils", - "serde", - "sp-api 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "substrate-prometheus-endpoint", - "thiserror", -] - -[[package]] -name = "sc-consensus-beefy-etf" -version = "13.0.0" -dependencies = [ - "ark-bls12-377", - "ark-serialize", - "array-bytes 6.2.3", - "async-channel", - "async-trait", - "fnv", - "futures", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-block-builder", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-gossip", - "sc-network-sync", - "sc-network-test", - "sc-network-types", - "sc-transaction-pool-api", - "sc-utils", - "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-arithmetic 23.0.0", - "sp-blockchain", - "sp-consensus", - "sp-consensus-beefy-etf", - "sp-consensus-grandpa", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-keyring 31.0.0", - "sp-keystore 0.34.0", - "sp-mmr-primitives", - "sp-runtime 31.0.1", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "substrate-prometheus-endpoint", - "substrate-test-runtime-client", - "tempfile", - "thiserror", - "tokio", - "w3f-bls", - "wasm-timer", -] - -[[package]] -name = "sc-executor" -version = "0.32.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-executor-common", - "sc-executor-polkavm", - "sc-executor-wasmtime", - "schnellru", - "sp-api 26.0.0", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-io 30.0.0", - "sp-panic-handler 13.0.0", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-trie 29.0.0", - "sp-version 29.0.0", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "tracing", -] - -[[package]] -name = "sc-executor-common" -version = "0.29.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "polkavm", - "sc-allocator", - "sp-maybe-compressed-blob", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror", - "wasm-instrument", -] - -[[package]] -name = "sc-executor-polkavm" -version = "0.29.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "log", - "polkavm", - "sc-executor-common", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "sc-executor-wasmtime" -version = "0.29.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "anyhow", - "cfg-if", - "libc", - "log", - "parking_lot 0.12.3", - "rustix 0.36.17", - "sc-allocator", - "sc-executor-common", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "wasmtime", -] - -[[package]] -name = "sc-informant" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "ansi_term", - "futures", - "futures-timer", - "log", - "sc-client-api", - "sc-network", - "sc-network-common", - "sc-network-sync", - "sp-blockchain", - "sp-runtime 31.0.1", -] - -[[package]] -name = "sc-keystore" -version = "25.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "ark-serialize", - "array-bytes 6.2.3", - "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk?branch=jg/debug)", - "log", - "parking_lot 0.12.3", - "serde_json", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "thiserror", - "w3f-bls", -] - -[[package]] -name = "sc-mixnet" -version = "0.4.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "arrayvec", - "blake2 0.10.6", - "bytes", - "futures", - "futures-timer", - "log", - "mixnet", - "multiaddr", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-client-api", - "sc-network", - "sc-network-types", - "sc-transaction-pool-api", - "sp-api 26.0.0", - "sp-consensus", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "sp-mixnet", - "sp-runtime 31.0.1", - "thiserror", -] - -[[package]] -name = "sc-network" -version = "0.34.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "async-channel", - "async-trait", - "asynchronous-codec", - "bytes", - "cid 0.9.0", - "either", - "fnv", - "futures", - "futures-timer", - "ip_network", - "libp2p", - "linked_hash_set", - "litep2p", - "log", - "mockall 0.11.4", - "once_cell", - "parity-scale-codec", - "parking_lot 0.12.3", - "partial_sort", - "pin-project", - "prost 0.12.6", - "prost-build 0.12.6", - "rand 0.8.5", - "sc-client-api", - "sc-network-common", - "sc-network-types", - "sc-utils", - "schnellru", - "serde", - "serde_json", - "smallvec", - "sp-arithmetic 23.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "substrate-prometheus-endpoint", - "thiserror", - "tokio", - "tokio-stream", - "unsigned-varint", - "void", - "wasm-timer", - "zeroize", -] - -[[package]] -name = "sc-network-common" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "bitflags 1.3.2", - "futures", - "libp2p-identity", - "parity-scale-codec", - "prost-build 0.12.6", - "sc-consensus", - "sc-network-types", - "sp-consensus", - "sp-consensus-grandpa", - "sp-runtime 31.0.1", -] - -[[package]] -name = "sc-network-gossip" -version = "0.34.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "ahash", - "futures", - "futures-timer", - "libp2p", - "log", - "sc-network", - "sc-network-common", - "sc-network-sync", - "sc-network-types", - "schnellru", - "sp-runtime 31.0.1", - "substrate-prometheus-endpoint", - "tracing", -] - -[[package]] -name = "sc-network-light" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "async-channel", - "futures", - "log", - "parity-scale-codec", - "prost 0.12.6", - "prost-build 0.12.6", - "sc-client-api", - "sc-network", - "sc-network-types", - "sp-blockchain", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "thiserror", -] - -[[package]] -name = "sc-network-sync" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "async-channel", - "async-trait", - "fork-tree", - "futures", - "futures-timer", - "libp2p", - "log", - "mockall 0.11.4", - "parity-scale-codec", - "prost 0.12.6", - "prost-build 0.12.6", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-types", - "sc-utils", - "schnellru", - "smallvec", - "sp-arithmetic 23.0.0", - "sp-blockchain", - "sp-consensus", - "sp-consensus-grandpa", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "substrate-prometheus-endpoint", - "thiserror", - "tokio", - "tokio-stream", -] - -[[package]] -name = "sc-network-test" -version = "0.8.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "libp2p", - "log", - "parking_lot 0.12.3", - "rand 0.8.5", - "sc-block-builder", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-light", - "sc-network-sync", - "sc-network-types", - "sc-service", - "sc-utils", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "substrate-test-runtime", - "substrate-test-runtime-client", - "tokio", -] - -[[package]] -name = "sc-network-transactions" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "futures", - "libp2p", - "log", - "parity-scale-codec", - "sc-network", - "sc-network-common", - "sc-network-sync", - "sc-network-types", - "sc-utils", - "sp-consensus", - "sp-runtime 31.0.1", - "substrate-prometheus-endpoint", -] - -[[package]] -name = "sc-network-types" -version = "0.10.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "bs58 0.5.1", - "ed25519-dalek 2.1.1", - "libp2p-identity", - "litep2p", - "multiaddr", - "multihash 0.17.0", - "rand 0.8.5", - "thiserror", - "zeroize", -] - -[[package]] -name = "sc-offchain" -version = "29.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "bytes", - "fnv", - "futures", - "futures-timer", - "hyper", - "hyper-rustls", - "libp2p", - "log", - "num_cpus", - "once_cell", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand 0.8.5", - "sc-client-api", - "sc-network", - "sc-network-common", - "sc-network-types", - "sc-transaction-pool-api", - "sc-utils", - "sp-api 26.0.0", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-keystore 0.34.0", - "sp-offchain", - "sp-runtime 31.0.1", - "threadpool", - "tracing", -] - -[[package]] -name = "sc-rpc" -version = "29.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "futures", - "jsonrpsee", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-block-builder", - "sc-chain-spec", - "sc-client-api", - "sc-mixnet", - "sc-rpc-api", - "sc-tracing", - "sc-transaction-pool-api", - "sc-utils", - "serde_json", - "sp-api 26.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "sp-offchain", - "sp-rpc", - "sp-runtime 31.0.1", - "sp-session", - "sp-statement-store", - "sp-version 29.0.0", - "tokio", -] - -[[package]] -name = "sc-rpc-api" -version = "0.33.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "jsonrpsee", - "parity-scale-codec", - "sc-chain-spec", - "sc-mixnet", - "sc-transaction-pool-api", - "scale-info", - "serde", - "serde_json", - "sp-core 28.0.0", - "sp-rpc", - "sp-runtime 31.0.1", - "sp-version 29.0.0", - "thiserror", -] - -[[package]] -name = "sc-rpc-server" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "forwarded-header-value", - "futures", - "governor", - "http", - "hyper", - "ip_network", - "jsonrpsee", - "log", - "serde", - "serde_json", - "substrate-prometheus-endpoint", - "tokio", - "tower", - "tower-http", -] - -[[package]] -name = "sc-rpc-spec-v2" -version = "0.34.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "futures", - "futures-util", - "hex", - "jsonrpsee", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand 0.8.5", - "sc-chain-spec", - "sc-client-api", - "sc-rpc", - "sc-transaction-pool-api", - "sc-utils", - "schnellru", - "serde", - "sp-api 26.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-rpc", - "sp-runtime 31.0.1", - "sp-version 29.0.0", - "thiserror", - "tokio", - "tokio-stream", -] - -[[package]] -name = "sc-service" -version = "0.35.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "directories", - "exit-future", - "futures", - "futures-timer", - "jsonrpsee", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "pin-project", - "rand 0.8.5", - "sc-chain-spec", - "sc-client-api", - "sc-client-db", - "sc-consensus", - "sc-executor", - "sc-informant", - "sc-keystore", - "sc-network", - "sc-network-common", - "sc-network-light", - "sc-network-sync", - "sc-network-transactions", - "sc-network-types", - "sc-rpc", - "sc-rpc-server", - "sc-rpc-spec-v2", - "sc-sysinfo", - "sc-telemetry", - "sc-tracing", - "sc-transaction-pool", - "sc-transaction-pool-api", - "sc-utils", - "schnellru", - "serde", - "serde_json", - "sp-api 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-state-machine 0.35.0", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-transaction-pool", - "sp-transaction-storage-proof", - "sp-trie 29.0.0", - "sp-version 29.0.0", - "static_init", - "substrate-prometheus-endpoint", - "tempfile", - "thiserror", - "tokio", - "tracing", - "tracing-futures", -] - -[[package]] -name = "sc-state-db" -version = "0.30.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "sp-core 28.0.0", -] - -[[package]] -name = "sc-sysinfo" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "derive_more 0.99.18", - "futures", - "libc", - "log", - "rand 0.8.5", - "rand_pcg", - "regex", - "sc-telemetry", - "serde", - "serde_json", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-io 30.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "sc-telemetry" -version = "15.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "chrono", - "futures", - "libp2p", - "log", - "parking_lot 0.12.3", - "pin-project", - "rand 0.8.5", - "sc-network", - "sc-utils", - "serde", - "serde_json", - "thiserror", - "wasm-timer", -] - -[[package]] -name = "sc-tracing" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "ansi_term", - "chrono", - "is-terminal", - "lazy_static", - "libc", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "regex", - "rustc-hash", - "sc-client-api", - "sc-tracing-proc-macro", - "serde", - "sp-api 26.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-rpc", - "sp-runtime 31.0.1", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror", - "tracing", - "tracing-log", - "tracing-subscriber 0.3.18", -] - -[[package]] -name = "sc-tracing-proc-macro" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.89", + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] -name = "sc-transaction-pool" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" dependencies = [ - "async-trait", "futures", - "futures-timer", - "linked-hash-map", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "sc-client-api", - "sc-transaction-pool-api", - "sc-utils", - "serde", - "sp-api 26.0.0", - "sp-blockchain", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime 31.0.1", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-transaction-pool", - "substrate-prometheus-endpoint", - "thiserror", + "pin-project", + "static_assertions", ] [[package]] -name = "sc-transaction-pool-api" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "safe-mix" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c" dependencies = [ - "async-trait", - "futures", - "log", - "parity-scale-codec", - "serde", - "sp-blockchain", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "thiserror", + "rustc_version 0.2.3", ] [[package]] -name = "sc-utils" -version = "14.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "safe_arch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" dependencies = [ - "async-channel", - "futures", - "futures-timer", - "lazy_static", - "log", - "parking_lot 0.12.3", - "prometheus", - "sp-arithmetic 23.0.0", + "bytemuck", ] [[package]] -name = "scale-bits" -version = "0.6.0" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "parity-scale-codec", - "scale-type-resolver", + "winapi-util", ] [[package]] -name = "scale-decode" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" +name = "sc-consensus-randomness-beacon" +version = "1.0.0" dependencies = [ - "derive_more 0.99.18", - "parity-scale-codec", - "scale-bits", - "scale-type-resolver", - "smallvec", + "async-std", + "futures", + "futures-timer", + "libp2p", + "log", + "prost", + "prost-types", + "rand 0.8.5", + "sp-consensus-randomness-beacon", + "tokio", ] [[package]] @@ -8109,7 +5722,7 @@ checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "bitvec", "cfg-if", - "derive_more 1.0.0", + "derive_more", "parity-scale-codec", "scale-info-derive", "serde", @@ -8121,27 +5734,12 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "scale-type-resolver" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "schnellru" version = "0.2.3" @@ -8162,52 +5760,27 @@ dependencies = [ "aead", "arrayref", "arrayvec", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "getrandom_or_panic", "merlin", "rand_core 0.6.4", "serde_bytes", "sha2 0.10.8", - "subtle 2.6.1", + "subtle", "zeroize", ] [[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scratch" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" - -[[package]] -name = "sct" -version = "0.7.1" +name = "scoped-tls" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] -name = "sctp-proto" -version = "0.2.2" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6220f78bb44c15f326b0596113305f6101097a18755d53727a575c97e09fb24" -dependencies = [ - "bytes", - "crc", - "fxhash", - "log", - "rand 0.8.5", - "slab", - "thiserror", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sec1" @@ -8217,10 +5790,10 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array", "pkcs8", "serdect", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -8251,38 +5824,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "0.9.0" @@ -8297,9 +5838,6 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] [[package]] name = "semver-parser" @@ -8377,31 +5915,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.1", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", - "sha1-asm", -] - [[package]] name = "sha1" version = "0.10.6" @@ -8413,15 +5926,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1-asm" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "286acebaf8b67c1130aedffad26f594eff0c1292389158135327d2e23aed582b" -dependencies = [ - "cc", -] - [[package]] name = "sha2" version = "0.9.9" @@ -8432,7 +5936,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug", ] [[package]] @@ -8472,10 +5976,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "signature" -version = "1.6.4" +name = "signal-hook-registry" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] [[package]] name = "signature" @@ -8500,27 +6007,12 @@ dependencies = [ "wide", ] -[[package]] -name = "simple-dns" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae9a3fcdadafb6d97f4c0e007e4247b114ee0f119f650c3cbf3a8b3a1479694" -dependencies = [ - "bitflags 2.6.0", -] - [[package]] name = "simple-mermaid" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "slab" version = "0.4.9" @@ -8530,12 +6022,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slice-group-by" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" - [[package]] name = "smallvec" version = "1.13.2" @@ -8543,10 +6029,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] -name = "snap" -version = "1.1.1" +name = "smol" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-fs", + "async-io 2.4.0", + "async-lock 3.4.0", + "async-net", + "async-process", + "blocking", + "futures-lite 2.5.0", +] [[package]] name = "snow" @@ -8555,14 +6052,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" dependencies = [ "aes-gcm", - "blake2 0.10.6", + "blake2", "chacha20poly1305", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "rand_core 0.6.4", "ring 0.17.8", "rustc_version 0.4.1", "sha2 0.10.8", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -8587,19 +6084,17 @@ dependencies = [ [[package]] name = "soketto" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "bytes", - "flate2", "futures", - "http", "httparse", "log", "rand 0.8.5", - "sha-1 0.9.8", + "sha1", ] [[package]] @@ -8622,7 +6117,7 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", "sp-trie 29.0.0", "sp-version 29.0.0", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -8645,7 +6140,7 @@ dependencies = [ "sp-state-machine 0.43.0", "sp-trie 37.0.0", "sp-version 37.0.0", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -8654,9 +6149,9 @@ version = "15.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "Inflector", - "blake2 0.10.6", + "blake2", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -8669,9 +6164,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9aadf9e97e694f0e343978aa632938c5de309cbcc8afed4136cb71596737278" dependencies = [ "Inflector", - "blake2 0.10.6", + "blake2", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -8726,107 +6221,30 @@ checksum = "46d0d0a4c591c421d3231ddd5e27d828618c24456d51445d21a1f79fcee97c23" dependencies = [ "docify", "integer-sqrt", - "num-traits", - "parity-scale-codec", - "scale-info", - "serde", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions", -] - -[[package]] -name = "sp-ark-bls12-381" -version = "0.4.2" -source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" -dependencies = [ - "ark-bls12-381-ext", - "sp-crypto-ec-utils", -] - -[[package]] -name = "sp-ark-ed-on-bls12-381-bandersnatch" -version = "0.4.2" -source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" -dependencies = [ - "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils", -] - -[[package]] -name = "sp-block-builder" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "sp-api 26.0.0", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", -] - -[[package]] -name = "sp-blockchain" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "futures", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "schnellru", - "sp-api 26.0.0", - "sp-consensus", - "sp-database", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "thiserror", -] - -[[package]] -name = "sp-consensus" -version = "0.32.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "futures", - "log", - "sp-core 28.0.0", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "thiserror", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions", ] [[package]] -name = "sp-consensus-aura" -version = "0.32.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "sp-ark-bls12-381" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ - "async-trait", - "parity-scale-codec", - "scale-info", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-consensus-slots", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "sp-timestamp", + "ark-bls12-381-ext", + "sp-crypto-ec-utils", ] [[package]] -name = "sp-consensus-babe" -version = "0.32.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "sp-ark-ed-on-bls12-381-bandersnatch" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ - "async-trait", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-consensus-slots", - "sp-core 28.0.0", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "sp-timestamp", + "ark-ed-on-bls12-381-bandersnatch-ext", + "sp-crypto-ec-utils", ] [[package]] @@ -8855,31 +6273,21 @@ dependencies = [ ] [[package]] -name = "sp-consensus-grandpa" -version = "13.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "finality-grandpa", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", -] - -[[package]] -name = "sp-consensus-slots" -version = "0.32.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "sp-consensus-randomness-beacon" +version = "1.0.0-dev" dependencies = [ + "ark-bls12-381", + "ark-serialize", + "array-bytes 6.2.3", + "async-trait", "parity-scale-codec", + "prost", + "prost-build", + "prost-types", "scale-info", "serde", - "sp-timestamp", + "sp-ark-bls12-381", + "sp-inherents 34.0.0", ] [[package]] @@ -8891,9 +6299,9 @@ dependencies = [ "array-bytes 6.2.3", "bandersnatch_vrfs", "bitflags 1.3.2", - "blake2 0.10.6", + "blake2", "bounded-collections", - "bs58 0.5.1", + "bs58", "dyn-clonable", "ed25519-zebra", "etf-crypto-primitives 0.2.4 (git+http://github.com/ideal-lab5/etf-sdk?branch=w3fbls-migration)", @@ -8908,7 +6316,7 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "paste", "primitive-types 0.12.2", "rand 0.8.5", @@ -8925,7 +6333,7 @@ dependencies = [ "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", "ss58-registry", "substrate-bip39 0.4.7", - "thiserror", + "thiserror 1.0.69", "tracing", "w3f-bls", "zeroize", @@ -8939,9 +6347,9 @@ checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7" dependencies = [ "array-bytes 6.2.3", "bitflags 1.3.2", - "blake2 0.10.6", + "blake2", "bounded-collections", - "bs58 0.5.1", + "bs58", "dyn-clonable", "ed25519-zebra", "futures", @@ -8955,7 +6363,7 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "paste", "primitive-types 0.12.2", "rand 0.8.5", @@ -8972,7 +6380,7 @@ dependencies = [ "sp-storage 21.0.0", "ss58-registry", "substrate-bip39 0.6.0", - "thiserror", + "thiserror 1.0.69", "tracing", "w3f-bls", "zeroize", @@ -9046,15 +6454,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-database" -version = "10.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "kvdb", - "parking_lot 0.12.3", -] - [[package]] name = "sp-debug-derive" version = "14.0.0" @@ -9152,7 +6551,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9166,7 +6565,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime 39.0.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9176,7 +6575,7 @@ source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1 dependencies = [ "bytes", "docify", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "libsecp256k1", "log", "parity-scale-codec", @@ -9204,7 +6603,7 @@ checksum = "59ef7eb561bb4839cc8424ce58c5ea236cbcca83f26fcc0426d8decfe8aa97d4" dependencies = [ "bytes", "docify", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "libsecp256k1", "log", "parity-scale-codec", @@ -9223,16 +6622,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "sp-keyring" -version = "31.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "strum 0.26.3", -] - [[package]] name = "sp-keyring" version = "39.0.0" @@ -9250,7 +6639,7 @@ version = "0.34.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "sp-core 28.0.0", "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] @@ -9262,26 +6651,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0248b4d784cb4a01472276928977121fa39d977a5bb24793b6b15e64b046df42" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "sp-core 34.0.0", "sp-externalities 0.29.0", ] -[[package]] -name = "sp-maybe-compressed-blob" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "thiserror", - "zstd 0.12.4", -] - [[package]] name = "sp-metadata-ir" version = "0.6.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "frame-metadata 16.0.0", + "frame-metadata", "parity-scale-codec", "scale-info", ] @@ -9292,20 +6672,9 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a616fa51350b35326682a472ee8e6ba742fdacb18babac38ecd46b3e05ead869" dependencies = [ - "frame-metadata 16.0.0", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "sp-mixnet" -version = "0.4.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ + "frame-metadata", "parity-scale-codec", "scale-info", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", ] [[package]] @@ -9322,7 +6691,7 @@ dependencies = [ "sp-core 28.0.0", "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", "sp-runtime 31.0.1", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9338,16 +6707,6 @@ dependencies = [ "sp-runtime 31.0.1", ] -[[package]] -name = "sp-offchain" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "sp-api 26.0.0", - "sp-core 28.0.0", - "sp-runtime 31.0.1", -] - [[package]] name = "sp-panic-handler" version = "13.0.0" @@ -9368,16 +6727,6 @@ dependencies = [ "regex", ] -[[package]] -name = "sp-rpc" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "rustc-hash", - "serde", - "sp-core 28.0.0", -] - [[package]] name = "sp-runtime" version = "31.0.1" @@ -9495,7 +6844,7 @@ source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1 dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -9508,7 +6857,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#a8722784fb36e13c811605b dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -9522,7 +6871,7 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", @@ -9577,14 +6926,14 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "rand 0.8.5", "smallvec", "sp-core 28.0.0", "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", "sp-panic-handler 13.0.0", "sp-trie 29.0.0", - "thiserror", + "thiserror 1.0.69", "tracing", "trie-db", ] @@ -9598,42 +6947,18 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "rand 0.8.5", "smallvec", "sp-core 34.0.0", "sp-externalities 0.29.0", "sp-panic-handler 13.0.1", "sp-trie 37.0.0", - "thiserror", + "thiserror 1.0.69", "tracing", "trie-db", ] -[[package]] -name = "sp-statement-store" -version = "10.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "aes-gcm", - "curve25519-dalek 4.1.3", - "ed25519-dalek 2.1.1", - "hkdf", - "parity-scale-codec", - "rand 0.8.5", - "scale-info", - "sha2 0.10.8", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime 31.0.1", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror", - "x25519-dalek 2.0.1", -] - [[package]] name = "sp-std" version = "14.0.0" @@ -9696,7 +7021,7 @@ dependencies = [ "parity-scale-codec", "sp-inherents 26.0.0", "sp-runtime 31.0.1", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9733,29 +7058,6 @@ dependencies = [ "tracing-subscriber 0.3.18", ] -[[package]] -name = "sp-transaction-pool" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "sp-api 26.0.0", - "sp-runtime 31.0.1", -] - -[[package]] -name = "sp-transaction-storage-proof" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "sp-trie 29.0.0", -] - [[package]] name = "sp-trie" version = "29.0.0" @@ -9767,13 +7069,13 @@ dependencies = [ "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "rand 0.8.5", "scale-info", "schnellru", "sp-core 28.0.0", "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror", + "thiserror 1.0.69", "tracing", "trie-db", "trie-root", @@ -9791,13 +7093,13 @@ dependencies = [ "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot", "rand 0.8.5", "scale-info", "schnellru", "sp-core 34.0.0", "sp-externalities 0.29.0", - "thiserror", + "thiserror 1.0.69", "tracing", "trie-db", "trie-root", @@ -9817,7 +7119,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", "sp-version-proc-macro 13.0.0", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9835,7 +7137,7 @@ dependencies = [ "sp-runtime 39.0.5", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-version-proc-macro 14.0.0", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -9866,11 +7168,9 @@ name = "sp-wasm-interface" version = "20.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", - "wasmtime", ] [[package]] @@ -9937,15 +7237,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spinning_top" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" -dependencies = [ - "lock_api", -] - [[package]] name = "spki" version = "0.7.3" @@ -9983,54 +7274,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "static_init" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" -dependencies = [ - "bitflags 1.3.2", - "cfg_aliases", - "libc", - "parking_lot 0.11.2", - "parking_lot_core 0.8.6", - "static_init_macro", - "winapi", -] - -[[package]] -name = "static_init_macro" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" -dependencies = [ - "cfg_aliases", - "memchr", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "str0m" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6706347e49b13373f7ddfafad47df7583ed52083d6fc8a594eb2c80497ef959d" -dependencies = [ - "combine", - "crc", - "fastrand", - "hmac 0.12.1", - "once_cell", - "openssl", - "openssl-sys", - "sctp-proto", - "serde", - "sha-1 0.10.1", - "thiserror", - "tracing", -] - [[package]] name = "strum" version = "0.24.1" @@ -10058,192 +7301,57 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.89", -] - -[[package]] -name = "substrate-bip39" -version = "0.4.7" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hmac 0.12.1", - "pbkdf2", - "schnorrkel", - "sha2 0.10.8", - "zeroize", -] - -[[package]] -name = "substrate-bip39" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca58ffd742f693dc13d69bdbb2e642ae239e0053f6aab3b104252892f856700a" -dependencies = [ - "hmac 0.12.1", - "pbkdf2", - "schnorrkel", - "sha2 0.10.8", - "zeroize", -] - -[[package]] -name = "substrate-prometheus-endpoint" -version = "0.17.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hyper", - "log", - "prometheus", - "thiserror", - "tokio", -] - -[[package]] -name = "substrate-test-client" -version = "2.0.1" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "array-bytes 6.2.3", - "async-trait", - "futures", - "parity-scale-codec", - "sc-client-api", - "sc-client-db", - "sc-consensus", - "sc-executor", - "sc-offchain", - "sc-service", - "serde", - "serde_json", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-keyring 31.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", - "sp-state-machine 0.35.0", - "tokio", + "rustversion", + "syn 1.0.109", ] [[package]] -name = "substrate-test-runtime" -version = "2.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "array-bytes 6.2.3", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support 28.0.0", - "frame-system 28.0.0", - "frame-system-rpc-runtime-api", - "hex-literal", - "log", - "pallet-babe", - "pallet-balances", - "pallet-timestamp", - "parity-scale-codec", - "sc-service", - "scale-info", - "serde_json", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-babe", - "sp-consensus-grandpa", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-genesis-builder 0.8.0", - "sp-inherents 26.0.0", - "sp-io 30.0.0", - "sp-keyring 31.0.0", - "sp-offchain", - "sp-runtime 31.0.1", - "sp-session", - "sp-state-machine 0.35.0", - "sp-transaction-pool", - "sp-trie 29.0.0", - "sp-version 29.0.0", - "substrate-wasm-builder", - "trie-db", + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.89", ] [[package]] -name = "substrate-test-runtime-client" -version = "2.0.0" +name = "substrate-bip39" +version = "0.4.7" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "futures", - "sc-block-builder", - "sc-client-api", - "sc-consensus", - "sp-api 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "substrate-test-client", - "substrate-test-runtime", + "hmac 0.12.1", + "pbkdf2", + "schnorrkel", + "sha2 0.10.8", + "zeroize", ] [[package]] -name = "substrate-test-utils" -version = "4.0.0-dev" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +name = "substrate-bip39" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca58ffd742f693dc13d69bdbb2e642ae239e0053f6aab3b104252892f856700a" dependencies = [ - "futures", - "tokio", + "hmac 0.12.1", + "pbkdf2", + "schnorrkel", + "sha2 0.10.8", + "zeroize", ] [[package]] -name = "substrate-wasm-builder" -version = "17.0.0" +name = "substrate-test-utils" +version = "4.0.0-dev" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ - "array-bytes 6.2.3", - "build-helper", - "cargo_metadata", - "console", - "filetime", - "frame-metadata 16.0.0", - "merkleized-metadata", - "parity-scale-codec", - "parity-wasm", - "polkavm-linker", - "sc-executor", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-maybe-compressed-blob", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-version 29.0.0", - "strum 0.26.3", - "tempfile", - "toml 0.8.19", - "walkdir", - "wasm-opt", + "futures", + "tokio", ] -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - [[package]] name = "subtle" version = "2.6.1" @@ -10272,18 +7380,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "synstructure" version = "0.13.1" @@ -10317,16 +7413,16 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "tagptr" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] -name = "target-lexicon" -version = "0.12.16" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-triple" @@ -10341,7 +7437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.2.0", "once_cell", "rustix 0.38.41", "windows-sys 0.59.0", @@ -10357,18 +7453,21 @@ dependencies = [ ] [[package]] -name = "termtree" -version = "0.4.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.11", ] [[package]] @@ -10383,22 +7482,24 @@ dependencies = [ ] [[package]] -name = "thread_local" -version = "1.1.8" +name = "thiserror-impl" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ - "cfg-if", - "once_cell", + "proc-macro2", + "quote", + "syn 2.0.89", ] [[package]] -name = "threadpool" -version = "1.8.1" +name = "thread_local" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "num_cpus", + "cfg-if", + "once_cell", ] [[package]] @@ -10448,7 +7549,7 @@ dependencies = [ "ark-std", "array-bytes 6.2.3", "chacha20poly1305", - "generic-array 0.14.7", + "generic-array", "parity-scale-codec", "rand_chacha 0.3.1", "rand_core 0.6.4", @@ -10476,7 +7577,7 @@ dependencies = [ "ark-std", "array-bytes 6.2.3", "chacha20poly1305", - "generic-array 0.14.7", + "generic-array", "parity-scale-codec", "rand_chacha 0.3.1", "rand_core 0.6.4", @@ -10525,16 +7626,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", "libc", "mio", - "parking_lot 0.12.3", - "pin-project-lite 0.2.15", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", "socket2 0.5.7", "tokio-macros", "windows-sys 0.52.0", @@ -10542,52 +7644,15 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" -dependencies = [ - "futures-core", - "pin-project-lite 0.2.15", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "rustls-native-certs", - "tokio", - "tokio-rustls", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.12" @@ -10596,21 +7661,11 @@ checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", - "pin-project-lite 0.2.15", + "pin-project-lite", "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.8.19" @@ -10638,7 +7693,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap", "serde", "serde_spanned", "toml_datetime", @@ -10658,45 +7713,6 @@ dependencies = [ "sha2 0.10.8", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite 0.2.15", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.6.0", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite 0.2.15", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - [[package]] name = "tower-service" version = "0.3.3" @@ -10705,21 +7721,21 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", - "pin-project-lite 0.2.15", + "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -10728,24 +7744,14 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -10761,142 +7767,49 @@ dependencies = [ name = "tracing-subscriber" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "parking_lot 0.12.3", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "time", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trie-db" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" -dependencies = [ - "hash-db", - "log", - "rustc-hex", - "smallvec", -] - -[[package]] -name = "trie-root" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" -dependencies = [ - "hash-db", -] - -[[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.5.1", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand 0.8.5", - "smallvec", - "socket2 0.4.10", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", ] [[package]] -name = "trust-dns-proto" -version = "0.23.2" +name = "tracing-subscriber" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.6.1", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", + "matchers", + "nu-ansi-term", "once_cell", - "rand 0.8.5", + "regex", + "sharded-slab", "smallvec", - "thiserror", - "tinyvec", - "tokio", + "thread_local", + "time", "tracing", - "url", + "tracing-core", + "tracing-log", ] [[package]] -name = "trust-dns-resolver" -version = "0.22.0" +name = "trie-db" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "lru-cache", - "parking_lot 0.12.3", - "resolv-conf", + "hash-db", + "log", + "rustc-hex", "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.22.0", ] [[package]] -name = "trust-dns-resolver" -version = "0.23.2" +name = "trie-root" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot 0.12.3", - "rand 0.8.5", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.23.2", + "hash-db", ] [[package]] @@ -10918,7 +7831,7 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml 0.8.19", + "toml", ] [[package]] @@ -10927,26 +7840,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.21.12", - "sha1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "twox-hash" version = "1.6.3" @@ -10955,7 +7848,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] @@ -10989,12 +7882,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" version = "1.0.14" @@ -11010,12 +7897,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-xid" version = "0.2.6" @@ -11029,7 +7910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -11037,13 +7918,12 @@ name = "unsigned-varint" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" -dependencies = [ - "asynchronous-codec", - "bytes", - "futures-io", - "futures-util", - "tokio-util", -] + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" [[package]] name = "untrusted" @@ -11064,16 +7944,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -11086,6 +7960,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "valuable" version = "0.1.0" @@ -11093,10 +7976,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] -name = "vcpkg" -version = "0.2.15" +name = "value-bag" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "version_check" @@ -11104,12 +7987,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "w3f-bls" version = "0.1.4" @@ -11130,377 +8007,117 @@ dependencies = [ "rand_core 0.6.4", "sha2 0.10.8", "sha3", - "thiserror", - "zeroize", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.89", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" - -[[package]] -name = "wasm-instrument" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" -dependencies = [ - "parity-wasm", -] - -[[package]] -name = "wasm-opt" -version = "0.116.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" -dependencies = [ - "anyhow", - "libc", - "strum 0.24.1", - "strum_macros 0.24.3", - "tempfile", - "thiserror", - "wasm-opt-cxx-sys", - "wasm-opt-sys", -] - -[[package]] -name = "wasm-opt-cxx-sys" -version = "0.116.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" -dependencies = [ - "anyhow", - "cxx", - "cxx-build", - "wasm-opt-sys", -] - -[[package]] -name = "wasm-opt-sys" -version = "0.116.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" -dependencies = [ - "anyhow", - "cc", - "cxx", - "cxx-build", -] - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasmparser" -version = "0.102.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" -dependencies = [ - "indexmap 1.9.3", - "url", -] - -[[package]] -name = "wasmtime" -version = "8.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f907fdead3153cb9bfb7a93bbd5b62629472dc06dee83605358c64c52ed3dda9" -dependencies = [ - "anyhow", - "bincode", - "cfg-if", - "indexmap 1.9.3", - "libc", - "log", - "object 0.30.4", - "once_cell", - "paste", - "psm", - "rayon", - "serde", - "target-lexicon", - "wasmparser", - "wasmtime-cache", - "wasmtime-cranelift", - "wasmtime-environ", - "wasmtime-jit", - "wasmtime-runtime", - "windows-sys 0.45.0", + "thiserror 1.0.69", + "zeroize", ] [[package]] -name = "wasmtime-asm-macros" -version = "8.0.1" +name = "waker-fn" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b9daa7c14cd4fa3edbf69de994408d5f4b7b0959ac13fa69d465f6597f810d" -dependencies = [ - "cfg-if", -] +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] -name = "wasmtime-cache" -version = "8.0.1" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "anyhow", - "base64 0.21.7", - "bincode", - "directories-next", - "file-per-thread-logger", - "log", - "rustix 0.36.17", - "serde", - "sha2 0.10.8", - "toml 0.5.11", - "windows-sys 0.45.0", - "zstd 0.11.2+zstd.1.5.2", + "same-file", + "winapi-util", ] [[package]] -name = "wasmtime-cranelift" -version = "8.0.1" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cefde0cce8cb700b1b21b6298a3837dba46521affd7b8c38a9ee2c869eee04" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "anyhow", - "cranelift-codegen", - "cranelift-entity", - "cranelift-frontend", - "cranelift-native", - "cranelift-wasm", - "gimli 0.27.3", - "log", - "object 0.30.4", - "target-lexicon", - "thiserror", - "wasmparser", - "wasmtime-cranelift-shared", - "wasmtime-environ", + "try-lock", ] [[package]] -name = "wasmtime-cranelift-shared" -version = "8.0.1" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd041e382ef5aea1b9fc78442394f1a4f6d676ce457e7076ca4cb3f397882f8b" -dependencies = [ - "anyhow", - "cranelift-codegen", - "cranelift-native", - "gimli 0.27.3", - "object 0.30.4", - "target-lexicon", - "wasmtime-environ", -] +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasmtime-environ" -version = "8.0.1" +name = "wasi" +version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a990198cee4197423045235bf89d3359e69bd2ea031005f4c2d901125955c949" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" dependencies = [ - "anyhow", - "cranelift-entity", - "gimli 0.27.3", - "indexmap 1.9.3", - "log", - "object 0.30.4", - "serde", - "target-lexicon", - "thiserror", - "wasmparser", - "wasmtime-types", + "wit-bindgen-rt", ] [[package]] -name = "wasmtime-jit" -version = "8.0.1" +name = "wasm-bindgen" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de48df552cfca1c9b750002d3e07b45772dd033b0b206d5c0968496abf31244" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ - "addr2line 0.19.0", - "anyhow", - "bincode", "cfg-if", - "cpp_demangle", - "gimli 0.27.3", - "log", - "object 0.30.4", - "rustc-demangle", - "serde", - "target-lexicon", - "wasmtime-environ", - "wasmtime-jit-debug", - "wasmtime-jit-icache-coherence", - "wasmtime-runtime", - "windows-sys 0.45.0", + "once_cell", + "wasm-bindgen-macro", ] [[package]] -name = "wasmtime-jit-debug" -version = "8.0.1" +name = "wasm-bindgen-backend" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ - "object 0.30.4", + "bumpalo", + "log", "once_cell", - "rustix 0.36.17", + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-shared", ] [[package]] -name = "wasmtime-jit-icache-coherence" -version = "8.0.1" +name = "wasm-bindgen-futures" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", - "libc", - "windows-sys 0.45.0", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "wasmtime-runtime" -version = "8.0.1" +name = "wasm-bindgen-macro" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658cf6f325232b6760e202e5255d823da5e348fdea827eff0a2a22319000b441" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ - "anyhow", - "cc", - "cfg-if", - "indexmap 1.9.3", - "libc", - "log", - "mach", - "memfd", - "memoffset", - "paste", - "rand 0.8.5", - "rustix 0.36.17", - "wasmtime-asm-macros", - "wasmtime-environ", - "wasmtime-jit-debug", - "windows-sys 0.45.0", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "wasmtime-types" -version = "8.0.1" +name = "wasm-bindgen-macro-support" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f6fffd2a1011887d57f07654dd112791e872e3ff4a2e626aee8059ee17f06f" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "cranelift-entity", - "serde", - "thiserror", - "wasmparser", + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + [[package]] name = "web-sys" version = "0.3.72" @@ -11512,35 +8129,20 @@ dependencies = [ ] [[package]] -name = "webpki" -version = "0.22.4" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "js-sys", + "wasm-bindgen", ] [[package]] name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "which" -version = "4.4.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.41", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "wide" @@ -11600,11 +8202,12 @@ dependencies = [ ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -11614,10 +8217,45 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" dependencies = [ - "windows-result", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.2.0", + "windows-strings", "windows-targets 0.52.6", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -11628,27 +8266,22 @@ dependencies = [ ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-result" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "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 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.6", ] [[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-strings" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-targets 0.42.2", + "windows-result 0.2.0", + "windows-targets 0.52.6", ] [[package]] @@ -11678,21 +8311,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "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 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -11724,12 +8342,6 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -11742,12 +8354,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -11760,12 +8366,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -11784,12 +8384,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -11802,12 +8396,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -11820,12 +8408,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -11838,12 +8420,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -11875,6 +8451,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -11896,24 +8481,13 @@ dependencies = [ "tap", ] -[[package]] -name = "x25519-dalek" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" -dependencies = [ - "curve25519-dalek 3.2.0", - "rand_core 0.5.1", - "zeroize", -] - [[package]] name = "x25519-dalek" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ - "curve25519-dalek 4.1.3", + "curve25519-dalek", "rand_core 0.6.4", "serde", "zeroize", @@ -11921,51 +8495,65 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ "asn1-rs", - "base64 0.13.1", "data-encoding", "der-parser", "lazy_static", "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] -name = "x509-parser" -version = "0.15.1" +name = "xml-rs" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror", - "time", + "xml-rs", ] [[package]] name = "yamux" -version = "0.10.2" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.3", + "parking_lot", + "pin-project", "rand 0.8.5", "static_assertions", + "web-time", ] [[package]] @@ -12004,7 +8592,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "synstructure 0.13.1", + "synstructure", ] [[package]] @@ -12014,7 +8602,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +dependencies = [ + "zerocopy-derive 0.8.17", ] [[package]] @@ -12028,6 +8625,17 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "zerofrom" version = "0.1.4" @@ -12046,7 +8654,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "synstructure 0.13.1", + "synstructure", ] [[package]] @@ -12090,51 +8698,3 @@ dependencies = [ "quote", "syn 2.0.89", ] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - -[[package]] -name = "zstd" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" -dependencies = [ - "zstd-safe 6.0.6", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-safe" -version = "6.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index a9d831c..53a0f3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "client/consensus/beefy-etf", "client/consensus/randomness-beacon", "primitives/consensus/beefy-etf", "primitives/consensus/randomness-beacon", diff --git a/client/consensus/beefy-etf/Cargo.toml b/client/consensus/beefy-etf/Cargo.toml deleted file mode 100644 index 034c8a9..0000000 --- a/client/consensus/beefy-etf/Cargo.toml +++ /dev/null @@ -1,72 +0,0 @@ -[package] -name = "sc-consensus-beefy-etf" -version = "13.0.0" -authors.workspace = true -edition.workspace = true -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -repository.workspace = true -description = "BEEFY Client gadget for substrate" -homepage = "https://substrate.io" - -[lints] -workspace = true - -[dependencies] -array-bytes = "6.1" -async-channel = "1.8.0" -async-trait = "0.1.74" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -fnv = "1.0.6" -futures = "0.3" -log = { workspace = true, default-features = true } -parking_lot = "0.12.1" -thiserror = { workspace = true } -wasm-timer = "0.2.5" -prometheus = { package = "substrate-prometheus-endpoint", git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-client-api = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-consensus = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-network = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-network-gossip = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-network-sync = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-network-types = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-utils = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-transaction-pool-api = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-api = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-application-crypto = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-arithmetic = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-blockchain = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-consensus = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-consensus-beefy-etf = { path = "../../../primitives/consensus/beefy-etf", features = ["bls-experimental"] } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-crypto-hashing = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-keystore = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", features = ["bls-experimental"]} -sp-mmr-primitives = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -tokio = "1.22.0" -ark-serialize = { version = "0.4.0" } -ark-bls12-377 = { version = "0.4.0", features = ["curve"], optional = true} -w3f-bls = { version = "0.1.3", optional = true } - - -[dev-dependencies] -serde = { workspace = true, default-features = true } -tempfile = "3.1.0" -sc-block-builder = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sc-network-test = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-consensus-grandpa = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-keyring = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-tracing = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -substrate-test-runtime-client = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } - -[features] -default = ["bls-experimental"] -# This feature adds BLS crypto primitives. It should not be used in production since -# the BLS implementation and interface may still be subject to significant change. -bls-experimental = [ - "sp-application-crypto/bls-experimental", - "sp-consensus-beefy-etf/bls-experimental", - "sp-core/bls-experimental", - "ark-bls12-377", - "w3f-bls" -] -full_crypto = [] diff --git a/client/consensus/beefy-etf/README.md b/client/consensus/beefy-etf/README.md deleted file mode 100644 index a7956cf..0000000 --- a/client/consensus/beefy-etf/README.md +++ /dev/null @@ -1,373 +0,0 @@ -# BEEFY -**BEEFY** (**B**ridge **E**fficiency **E**nabling **F**inality **Y**ielder) is a secondary -protocol running along GRANDPA Finality to support efficient bridging with non-Substrate -blockchains, currently mainly ETH mainnet. - -It can be thought of as an (optional) Bridge-specific Gadget to the GRANDPA Finality protocol. -The Protocol piggybacks on many assumptions provided by GRANDPA, and is required to be built -on top of it to work correctly. - -BEEFY is a consensus protocol designed with efficient trustless bridging in mind. It means -that building a light client of BEEFY protocol should be optimized for restricted environments -like Ethereum Smart Contracts or On-Chain State Transition Function (e.g. Substrate Runtime). -Note that BEEFY is not a standalone protocol, it is meant to be running alongside GRANDPA, a -finality gadget created for Substrate/Polkadot ecosystem. More details about GRANDPA can be found -in the [whitepaper](https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf). - -# Context - -## Bridges - -We want to be able to "bridge" different blockchains. We do so by safely sharing and verifying -information about each chain’s state, i.e. blockchain `A` should be able to verify that blockchain -`B` is at block #X. - -## Finality - -Finality in blockchains is a concept that means that after a given block #X has been finalized, -it will never be reverted (e.g. due to a re-org). As such, we can be assured that any transaction -that exists in this block will never be reverted. - -## GRANDPA - -GRANDPA is our finality gadget. It allows a set of nodes to come to BFT agreement on what is the -canonical chain. It requires that 2/3 of the validator set agrees on a prefix of the canonical -chain, which then becomes finalized. - -![img](https://miro.medium.com/max/955/1*NTg26i4xbO3JncF_Usu9MA.png) - -### Difficulties of GRANDPA finality proofs - -```rust -struct Justification { - round: u64, - commit: Commit, - votes_ancestries: Vec, -} - -struct Commit { - target_hash: Hash, - target_number: Number, - precommits: Vec>, -} - -struct SignedPrecommit { - precommit: Precommit, - signature: Signature, - id: Id, -} - -struct Precommit { - target_hash: Hash, - target_number: Number, -} -``` - -The main difficulty of verifying GRANDPA finality proofs comes from the fact that voters are -voting on different things. In GRANDPA each voter will vote for the block they think is the -latest one, and the protocol will come to agreement on what is the common ancestor which has > -2/3 support. - -This creates two sets of inefficiencies: - -- We may need to have each validator's vote data because they're all potentially different (i.e. - just the signature isn't enough). -- We may need to attach a couple of headers to the finality proof in order to be able to verify - all of the votes' ancestries. - -Additionally, since our interim goal is to bridge to Ethereum there is also a difficulty related -to "incompatible" crypto schemes. We use \`ed25519\` signatures in GRANDPA which we can't -efficiently verify in the EVM. - -Hence, - -### Goals of BEEFY - -1. Allow customisation of crypto to adapt for different targets. Support thresholds signatures as - well eventually. -1. Minimize the size of the "signed payload" and the finality proof. -1. Unify data types and use backward-compatible versioning so that the protocol can be extended - (additional payload, different crypto) without breaking existing light clients. - -And since BEEFY is required to be running on top of GRANDPA. This allows us to take couple of -shortcuts: -1. BEEFY validator set is **the same** as GRANDPA's (i.e. the same bonded actors), they might be - identified by different session keys though. -1. BEEFY runs on **finalized** canonical chain, i.e. no forks (note Misbehavior - section though). -1. From a single validator perspective, BEEFY has at most one active voting round. Since GRANDPA - validators are reaching finality, we assume they are on-line and well-connected and have - similar view of the state of the blockchain. - -# The BEEFY Protocol - -## Mental Model - -BEEFY should be considered as an extra voting round done by GRANDPA validators for the current -best finalized block. Similarly to how GRANDPA is lagging behind best produced (non-finalized) -block, BEEFY is going to lag behind best GRANDPA (finalized) block. - -``` - ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ - │ │ │ │ │ │ │ │ │ │ - │ B1 │ │ B2 │ │ B3 │ │ B4 │ │ B5 │ - │ │ │ │ │ │ │ │ │ │ - └──────┘ └───▲──┘ └──────┘ └───▲──┘ └───▲──┘ - │ │ │ - Best BEEFY block───────────────┘ │ │ - │ │ - Best GRANDPA block───────────────────────────────┘ │ - │ - Best produced block───────────────────────────────────────┘ - -``` - -A pseudo-algorithm of behaviour for a fully-synced BEEFY validator is: - -``` -loop { - let (best_beefy, best_grandpa) = wait_for_best_blocks(); - - let block_to_vote_on = choose_next_beefy_block( - best_beefy, - best_grandpa - ); - - let payload_to_vote_on = retrieve_payload(block_to_vote_on); - - let commitment = (block_to_vote_on, payload_to_vote_on); - - let signature = sign_with_current_session_key(commitment); - - broadcast_vote(commitment, signature); -} -``` - -## Details - -Before we jump into describing how BEEFY works in details, let's agree on the terms we are going -to use and actors in the system. All nodes in the network need to participate in the BEEFY -networking protocol, but we can identify two distinct actors though: **regular nodes** and -**BEEFY validators**. -Validators are expected to actively participate in the protocol, by producing and broadcasting -**votes**. Votes are simply their signatures over a **Commitment**. A Commitment consists of a -**payload** (an opaque blob of bytes extracted from a block or state at that block, expected to -be some form of crypto accumulator (like Merkle Tree Hash or Merkle Mountain Range Root Hash)) -and **block number** from which this payload originates. Additionally, Commitment contains BEEFY -**validator set id** at that particular block. Note the block is finalized, so there is no -ambiguity despite using block number instead of a hash. A collection of **votes**, or rather -a Commitment and a collection of signatures is going to be called **Signed Commitment**. A valid -(see later for the rules) Signed Commitment is also called a **BEEFY Justification** or -**BEEFY Finality Proof**. For more details on the actual data structures please see -[BEEFY primitives definitions](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/primitives/beefy/src). - -A **round** is an attempt by BEEFY validators to produce a BEEFY Justification. **Round number** -is simply defined as a block number the validators are voting for, or to be more precise, the -Commitment for that block number. Round ends when the next round is started, which may happen -when one of the events occur: -1. Either the node collects `2/3rd + 1` valid votes for that round. -2. Or the node receives a BEEFY Justification for a block greater than the current best BEEFY block. - -In both cases the node proceeds to determining the new round number using "Round Selection" -procedure. - -Regular nodes are expected to: -1. Receive & validate votes for the current round and broadcast them to their peers. -1. Receive & validate BEEFY Justifications and broadcast them to their peers. -1. Return BEEFY Justifications for **Mandatory Blocks** on demand. -1. Optionally return BEEFY Justifications for non-mandatory blocks on demand. - -Validators are expected to additionally: -1. Produce & broadcast vote for the current round. - -Both kinds of actors are expected to fully participate in the protocol ONLY IF they believe they -are up-to-date with the rest of the network, i.e. they are fully synced. Before this happens, -the node should continue processing imported BEEFY Justifications and votes without actively -voting themselves. - -### Round Selection - -Every node (both regular nodes and validators) need to determine locally what they believe -current round number is. The choice is based on their knowledge of: - -1. Best GRANDPA finalized block number (`best_grandpa`). -1. Best BEEFY finalized block number (`best_beefy`). -1. Starting block of current session (`session_start`). - -**Session** means a period of time (or rather number of blocks) where validator set (keys) do not change. -See `pallet_session` for implementation details in `FRAME` context. Since we piggy-back on -GRANDPA, session boundaries for BEEFY are exactly the same as the ones for GRANDPA. - -We define two kinds of blocks from the perspective of BEEFY protocol: -1. **Mandatory Blocks** -2. **Non-mandatory Blocks** - -Mandatory blocks are the ones that MUST have BEEFY justification. That means that the validators -will always start and conclude a round at mandatory blocks. For non-mandatory blocks, there may -or may not be a justification and validators may never choose these blocks to start a round. - -Every **first block in** each **session** is considered a **mandatory block**. All other blocks -in the session are non-mandatory, however validators are encouraged to finalize as many blocks as -possible to enable lower latency for light clients and hence end users. Since GRANDPA is -considering session boundary blocks as mandatory as well, `session_start` block will always have -both GRANDPA and BEEFY Justification. - -Therefore, to determine current round number nodes use a formula: - -``` -round_number = - (1 - M) * session_start - + M * (best_beefy + NEXT_POWER_OF_TWO((best_grandpa - best_beefy + 1) / 2)) -``` - -where: - -- `M` is `1` if mandatory block in current session is already finalized and `0` otherwise. -- `NEXT_POWER_OF_TWO(x)` returns the smallest number greater or equal to `x` that is a power of two. - -In other words, the next round number should be the oldest mandatory block without a justification, -or the highest GRANDPA-finalized block, whose block number difference with `best_beefy` block is -a power of two. The mental model for round selection is to first finalize the mandatory block and -then to attempt to pick a block taking into account how fast BEEFY catches up with GRANDPA. -In case GRANDPA makes progress, but BEEFY seems to be lagging behind, validators are changing -rounds less often to increase the chance of concluding them. - -As mentioned earlier, every time the node picks a new `round_number` (and validator casts a vote) -it ends the previous one, no matter if finality was reached (i.e. the round concluded) or not. -Votes for an inactive round should not be propagated. - -Note that since BEEFY only votes for GRANDPA-finalized blocks, `session_start` here actually means: -"the latest session for which the start of is GRANDPA-finalized", i.e. block production might -have already progressed, but BEEFY needs to first finalize the mandatory block of the older -session. - -In good networking conditions BEEFY may end up finalizing each and every block (if GRANDPA does -the same). Practically, with short block times, it's going to be rare and might be excessive, so -it's suggested for implementations to introduce a `min_delta` parameter which will limit the -frequency with which new rounds are started. The affected component of the formula would be: -`best_beefy + MAX(min_delta, NEXT_POWER_OF_TWO(...))`, so we start a new round only if the -power-of-two component is greater than the min delta. Note that if `round_number > best_grandpa` -the validators are not expected to start any round. - -### Catch up - -Every session is guaranteed to have at least one BEEFY-finalized block. However it also means -that the round at mandatory block must be concluded even though, a new session has already started -(i.e. the on-chain component has selected a new validator set and GRANDPA might have already -finalized the transition). In such case BEEFY must "catch up" the previous sessions and make sure to -conclude rounds for mandatory blocks. Note that older sessions must obviously be finalized by the -validator set at that point in time, not the latest/current one. - -### Initial Sync - -It's all rainbows and unicorns when the node is fully synced with the network. However during cold -startup it will have hard time determining the current round number. Because of that nodes that -are not fully synced should not participate in BEEFY protocol at all. - -During the sync we should make sure to also fetch BEEFY justifications for all mandatory blocks. -This can happen asynchronously, but validators, before starting to vote, need to be certain -about the last session that contains a concluded round on mandatory block in order to initiate the -catch up procedure. - -### Gossip - -Nodes participating in BEEFY protocol are expected to gossip messages around. -The protocol defines following messages: - -1. Votes for the current round, -2. BEEFY Justifications for recently concluded rounds, -3. BEEFY Justification for the latest mandatory block, - -Each message is additionally associated with a **topic**, which can be either: -1. the round number (i.e. topic associated with a particular round), -2. or the global topic (independent from the rounds). - -Round-specific topic should only be used to gossip the votes, other messages are gossiped -periodically on the global topic. Let's now dive into description of the messages. - -- **Votes** - - Votes are sent on the round-specific topic. - - Vote is considered valid when: - - The commitment matches local commitment. - - The validator is part of the current validator set. - - The signature is correct. - -- **BEEFY Justification** - - Justifications are sent on the global topic. - - Justification is considered worthwhile to gossip when: - - It is for a recent (implementation specific) round or the latest mandatory round. - - All signatures are valid and there is at least `2/3rd + 1` of them. - - Signatories are part of the current validator set. - - Mandatory justifications should be announced periodically. - -## Misbehavior - -Similarly to other PoS protocols, BEEFY considers casting two different votes in the same round a -misbehavior. I.e. for a particular `round_number`, the validator produces signatures for 2 different -`Commitment`s and broadcasts them. This is called **equivocation**. - -On top of this, voting on an incorrect **payload** is considered a misbehavior as well, and since -we piggy-back on GRANDPA there is no ambiguity in terms of the fork validators should be voting for. - -Misbehavior should be penalized. If more validators misbehave in the exact same `round` the -penalty should be more severe, up to the entire bonded stake in case we reach `1/3rd + 1` -validators misbehaving. - -## Ethereum - -Initial version of BEEFY was made to enable efficient bridging with Ethereum, where the light -client is a Solidity Smart Contract compiled to EVM bytecode. Hence the choice of the initial -cryptography for BEEFY: `secp256k1` and usage of `keccak256` hashing function. - -### Future: Supporting multiple crypto - -While BEEFY currently works with `secp256k1` signatures, we intend in the future to support -multiple signature schemes. -This means that multiple kinds of `SignedCommitment`s might exist and only together they form a -full `BEEFY Justification`. - -## BEEFY Key - -The current cryptographic scheme used by BEEFY is `ecdsa`. This is **different** from other -schemes like `sr25519` and `ed25519` which are commonly used in Substrate configurations for -other pallets (BABE, GRANDPA, AuRa, etc). The most noticeable difference is that an `ecdsa` -public key is `33` bytes long, instead of `32` bytes for a `sr25519` based public key. So, a -BEEFY key [sticks out](https://github.com/paritytech/polkadot/blob/25951e45b1907853f120c752aaa01631a0b3e783/node/service/src/chain_spec.rs#L738) -among the other public keys a bit. - -For other crypto (using the default Substrate configuration) the `AccountId` (32-bytes) matches -the `PublicKey`, but note that it's not the case for BEEFY. As a consequence of this, you can -**not** convert the `AccountId` raw bytes into a BEEFY `PublicKey`. - -The easiest way to generate or view hex-encoded or SS58-encoded BEEFY Public Key is by using the -[Subkey](https://substrate.dev/docs/en/knowledgebase/integrate/subkey) tool. Generate a BEEFY key -using the following command - -```sh -subkey generate --scheme ecdsa -``` - -The output will look something like - -```sh -Secret phrase `sunset anxiety liberty mention dwarf actress advice stove peasant olive kite rebuild` is account: - Secret seed: 0x9f844e21444683c8fcf558c4c11231a14ed9dea6f09a8cc505604368ef204a61 - Public key (hex): 0x02d69740c3bbfbdbb365886c8270c4aafd17cbffb2e04ecef581e6dced5aded2cd - Public key (SS58): KW7n1vMENCBLQpbT5FWtmYWHNvEyGjSrNL4JE32mDds3xnXTf - Account ID: 0x295509ae9a9b04ade5f1756b5f58f4161cf57037b4543eac37b3b555644f6aed - SS58 Address: 5Czu5hudL79ETnQt6GAkVJHGhDQ6Qv3VWq54zN1CPKzKzYGu - -``` - -In case your BEEFY keys are using the wrong cryptographic scheme, you will see an invalid public -key format message at node startup. Basically something like - -```sh -... -2021-05-28 12:37:51 [Relaychain] Invalid BEEFY PublicKey format! -... -``` - -# BEEFY Light Client - -TODO diff --git a/client/consensus/beefy-etf/src/aux_schema.rs b/client/consensus/beefy-etf/src/aux_schema.rs deleted file mode 100644 index 534f668..0000000 --- a/client/consensus/beefy-etf/src/aux_schema.rs +++ /dev/null @@ -1,106 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Schema for BEEFY state persisted in the aux-db. - -use crate::{error::Error, worker::PersistedState, LOG_TARGET}; -use codec::{Decode, Encode}; -use log::{debug, trace}; -use sc_client_api::{backend::AuxStore, Backend}; -use sp_runtime::traits::Block as BlockT; - -const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; -const WORKER_STATE_KEY: &[u8] = b"beefy_voter_state"; - -const CURRENT_VERSION: u32 = 4; - -pub(crate) fn write_current_version(backend: &BE) -> Result<(), Error> { - debug!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); - AuxStore::insert_aux(backend, &[(VERSION_KEY, CURRENT_VERSION.encode().as_slice())], &[]) - .map_err(|e| Error::Backend(e.to_string())) -} - -/// Write voter state. -pub(crate) fn write_voter_state( - backend: &BE, - state: &PersistedState, -) -> Result<(), Error> { - trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); - AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) - .map_err(|e| Error::Backend(e.to_string())) -} - -fn load_decode(backend: &BE, key: &[u8]) -> Result, Error> { - match backend.get_aux(key).map_err(|e| Error::Backend(e.to_string()))? { - None => Ok(None), - Some(t) => T::decode(&mut &t[..]) - .map_err(|e| Error::Backend(format!("BEEFY DB is corrupted: {}", e))) - .map(Some), - } -} - -/// Load or initialize persistent data from backend. -pub(crate) fn load_persistent(backend: &BE) -> Result>, Error> -where - B: BlockT, - BE: Backend, -{ - let version: Option = load_decode(backend, VERSION_KEY)?; - - match version { - None => (), - Some(1) | Some(2) | Some(3) => (), // versions 1, 2 & 3 are obsolete and should be ignored - Some(4) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), - other => return Err(Error::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), - } - - // No persistent state found in DB. - Ok(None) -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::tests::BeefyTestNet; - use sc_network_test::TestNetFactory; - - // 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); - let backend = net.peer(0).client().as_backend(); - - // version not available in db -> None - assert_eq!(load_persistent(&*backend).unwrap(), None); - - // populate version in db - write_current_version(&*backend).unwrap(); - // verify correct version is retrieved - 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); - - // full `PersistedState` load is tested in `tests.rs`. - } -} diff --git a/client/consensus/beefy-etf/src/communication/gossip.rs b/client/consensus/beefy-etf/src/communication/gossip.rs deleted file mode 100644 index 994fad3..0000000 --- a/client/consensus/beefy-etf/src/communication/gossip.rs +++ /dev/null @@ -1,796 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use std::{collections::BTreeSet, sync::Arc, time::Duration}; - -use sc_network::{PeerId, ReputationChange}; -use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; -use sp_runtime::traits::{Block, Hash, Header, NumberFor}; - -use codec::{Decode, DecodeAll, Encode}; -use log::{debug, info, trace}; -use parking_lot::{Mutex, RwLock}; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use wasm_timer::Instant; - -use crate::{ - communication::{ - benefit, cost, - peers::{KnownPeers, PeerReport}, - }, - justification::{ - proof_block_num_and_set_id, verify_with_validator_set, BeefyVersionedFinalityProof, - }, - keystore::BeefyKeystore, - LOG_TARGET, -}; - -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::{AuthorityId, Signature}; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::ecdsa_crypto::{AuthorityId, Signature}; - -use sp_consensus_beefy_etf::{ValidatorSet, ValidatorSetId, VoteMessage}; - -// Timeout for rebroadcasting messages. -#[cfg(not(test))] -const REBROADCAST_AFTER: Duration = Duration::from_secs(60); -#[cfg(test)] -const REBROADCAST_AFTER: Duration = Duration::from_secs(5); - -#[derive(Debug, PartialEq)] -pub(super) enum Action { - // repropagate under given topic, to the given peers, applying cost/benefit to originator. - Keep(H, ReputationChange), - // discard, applying cost/benefit to originator. - Discard(ReputationChange), - // ignore, no cost/benefit applied to originator. - DiscardNoReport, -} - -/// An outcome of examining a message. -#[derive(Debug, PartialEq, Clone, Copy)] -enum Consider { - /// Accept the message. - Accept, - /// Message is too early. Reject. - RejectPast, - /// Message is from the future. Reject. - RejectFuture, - /// Message cannot be evaluated. Reject. - CannotEvaluate, -} - -/// BEEFY gossip message type that gets encoded and sent on the network. -#[derive(Debug, Encode, Decode)] -pub(crate) enum GossipMessage { - /// BEEFY message with commitment and single signature. - Vote(VoteMessage, AuthorityId, Signature>), - /// BEEFY justification with commitment and signatures. - FinalityProof(BeefyVersionedFinalityProof), -} - -impl GossipMessage { - /// Return inner vote if this message is a Vote. - pub fn unwrap_vote(self) -> Option, AuthorityId, Signature>> { - match self { - GossipMessage::Vote(vote) => Some(vote), - GossipMessage::FinalityProof(_) => None, - } - } - - /// Return inner finality proof if this message is a FinalityProof. - pub fn unwrap_finality_proof(self) -> Option> { - match self { - GossipMessage::Vote(_) => None, - GossipMessage::FinalityProof(proof) => Some(proof), - } - } -} - -/// Gossip engine votes messages topic -pub(crate) fn votes_topic() -> B::Hash -where - B: Block, -{ - <::Hashing as Hash>::hash(b"beefy-votes") -} - -/// Gossip engine justifications messages topic -pub(crate) fn proofs_topic() -> B::Hash -where - B: Block, -{ - <::Hashing as Hash>::hash(b"beefy-justifications") -} - -#[derive(Clone, Debug)] -pub(crate) struct GossipFilterCfg<'a, B: Block> { - pub start: NumberFor, - pub end: NumberFor, - pub validator_set: &'a ValidatorSet, -} - -#[derive(Clone, Debug)] -struct FilterInner { - pub start: NumberFor, - pub end: NumberFor, - pub validator_set: ValidatorSet, -} - -struct Filter { - // specifies live rounds - inner: Option>, - // cache of seen valid justifications in active rounds - rounds_with_valid_proofs: BTreeSet>, -} - -impl Filter { - pub fn new() -> Self { - Self { inner: None, rounds_with_valid_proofs: BTreeSet::new() } - } - - /// Update filter to new `start` and `set_id`. - fn update(&mut self, cfg: GossipFilterCfg) { - self.rounds_with_valid_proofs - .retain(|&round| round >= cfg.start && round <= cfg.end); - // only clone+overwrite big validator_set if set_id changed - match self.inner.as_mut() { - Some(f) if f.validator_set.id() == cfg.validator_set.id() => { - f.start = cfg.start; - f.end = cfg.end; - }, - _ => - self.inner = Some(FilterInner { - start: cfg.start, - end: cfg.end, - validator_set: cfg.validator_set.clone(), - }), - } - } - - /// Accept if `max(session_start, best_beefy) <= round <= best_grandpa`, - /// and vote `set_id` matches session set id. - /// - /// Latest concluded round is still considered alive to allow proper gossiping for it. - fn consider_vote(&self, round: NumberFor, set_id: ValidatorSetId) -> Consider { - self.inner - .as_ref() - .map(|f| - // only from current set and only [filter.start, filter.end] - if set_id < f.validator_set.id() || round < f.start { - Consider::RejectPast - } else if set_id > f.validator_set.id() || round > f.end { - Consider::RejectFuture - } else { - Consider::Accept - }) - .unwrap_or(Consider::CannotEvaluate) - } - - /// Return true if `round` is >= than `max(session_start, best_beefy)`, - /// and proof `set_id` matches session set id. - /// - /// Latest concluded round is still considered alive to allow proper gossiping for it. - fn consider_finality_proof(&self, round: NumberFor, set_id: ValidatorSetId) -> Consider { - self.inner - .as_ref() - .map(|f| - // only from current set and only >= filter.start - if round < f.start || set_id < f.validator_set.id() { - Consider::RejectPast - } else if set_id > f.validator_set.id() { - Consider::RejectFuture - } else { - Consider::Accept - } - ) - .unwrap_or(Consider::CannotEvaluate) - } - - /// Add new _known_ `round` to the set of seen valid justifications. - fn mark_round_as_proven(&mut self, round: NumberFor) { - self.rounds_with_valid_proofs.insert(round); - } - - /// Check if `round` is already part of seen valid justifications. - fn is_already_proven(&self, round: NumberFor) -> bool { - self.rounds_with_valid_proofs.contains(&round) - } - - fn validator_set(&self) -> Option<&ValidatorSet> { - self.inner.as_ref().map(|f| &f.validator_set) - } -} - -/// BEEFY gossip validator -/// -/// Validate BEEFY gossip messages and limit the number of live BEEFY voting rounds. -/// -/// Allows messages for 'rounds >= last concluded' to flow, everything else gets -/// rejected/expired. -/// -///All messaging is handled in a single BEEFY global topic. -pub(crate) struct GossipValidator -where - B: Block, -{ - votes_topic: B::Hash, - justifs_topic: B::Hash, - gossip_filter: RwLock>, - next_rebroadcast: Mutex, - known_peers: Arc>>, - report_sender: TracingUnboundedSender, -} - -impl GossipValidator -where - B: Block, -{ - pub(crate) fn new( - known_peers: Arc>>, - ) -> (GossipValidator, TracingUnboundedReceiver) { - let (tx, rx) = tracing_unbounded("mpsc_beefy_gossip_validator", 100_000); - let val = GossipValidator { - votes_topic: votes_topic::(), - justifs_topic: proofs_topic::(), - gossip_filter: RwLock::new(Filter::new()), - next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), - known_peers, - report_sender: tx, - }; - (val, rx) - } - - /// Update gossip validator filter. - /// - /// Only votes for `set_id` and rounds `start <= round <= end` will be accepted. - pub(crate) fn update_filter(&self, filter: GossipFilterCfg) { - debug!( - target: LOG_TARGET, - "🥩 New gossip filter: start {:?}, end {:?}, validator set id {:?}", - filter.start, filter.end, filter.validator_set.id() - ); - self.gossip_filter.write().update(filter); - } - - fn report(&self, who: PeerId, cost_benefit: ReputationChange) { - let _ = self.report_sender.unbounded_send(PeerReport { who, cost_benefit }); - } - - fn validate_vote( - &self, - vote: VoteMessage, AuthorityId, Signature>, - sender: &PeerId, - ) -> Action { - let round = vote.commitment.block_number; - let set_id = vote.commitment.validator_set_id; - self.known_peers.lock().note_vote_for(*sender, round); - - // Verify general usefulness of the message. - // We are going to discard old votes right away (without verification). - { - let filter = self.gossip_filter.read(); - - match filter.consider_vote(round, set_id) { - Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), - Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), - // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we - // discard the vote without punishing or rewarding the sending peer. - Consider::CannotEvaluate => return Action::DiscardNoReport, - Consider::Accept => {}, - } - - // ensure authority is part of the set. - if !filter - .validator_set() - .map(|set| set.validators().contains(&vote.id)) - .unwrap_or(false) - { - debug!(target: LOG_TARGET, "Message from voter not in validator set: {}", vote.id); - return Action::Discard(cost::UNKNOWN_VOTER); - } - } - - if BeefyKeystore::verify(&vote.id, &vote.signature, &vote.commitment.encode()) { - info!( - target: LOG_TARGET, - "🎲 The etf signature was verified", - ); - Action::Keep(self.votes_topic, benefit::VOTE_MESSAGE) - } else { - debug!( - target: LOG_TARGET, - "🥩 Bad signature on message: {:?}, from: {:?}", vote, sender - ); - Action::Discard(cost::BAD_SIGNATURE) - } - } - - fn validate_finality_proof( - &self, - proof: BeefyVersionedFinalityProof, - sender: &PeerId, - ) -> Action { - let (round, set_id) = proof_block_num_and_set_id::(&proof); - self.known_peers.lock().note_vote_for(*sender, round); - - let action = { - let guard = self.gossip_filter.read(); - - // Verify general usefulness of the justification. - match guard.consider_finality_proof(round, set_id) { - Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), - Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), - // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we - // discard the proof without punishing or rewarding the sending peer. - Consider::CannotEvaluate => return Action::DiscardNoReport, - Consider::Accept => {}, - } - - if guard.is_already_proven(round) { - return Action::Discard(benefit::NOT_INTERESTED); - } - - // Verify justification signatures. - guard - .validator_set() - .map(|validator_set| { - if let Err((_, signatures_checked)) = - verify_with_validator_set::(round, validator_set, &proof) - { - debug!( - target: LOG_TARGET, - "🥩 Bad signatures on message: {:?}, from: {:?}", proof, sender - ); - let mut cost = cost::INVALID_PROOF; - cost.value += - cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); - Action::Discard(cost) - } else { - Action::Keep(self.justifs_topic, benefit::VALIDATED_PROOF) - } - }) - // When we can't evaluate, it's our fault (e.g. filter not initialized yet), we - // discard the proof without punishing or rewarding the sending peer. - .unwrap_or(Action::DiscardNoReport) - }; - if matches!(action, Action::Keep(_, _)) { - self.gossip_filter.write().mark_round_as_proven(round); - } - action - } -} - -impl Validator for GossipValidator -where - B: Block, -{ - fn peer_disconnected(&self, _context: &mut dyn ValidatorContext, who: &PeerId) { - self.known_peers.lock().remove(who); - } - - fn validate( - &self, - context: &mut dyn ValidatorContext, - sender: &PeerId, - mut data: &[u8], - ) -> ValidationResult { - let raw = data; - let action = match GossipMessage::::decode_all(&mut data) { - Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender), - Ok(GossipMessage::FinalityProof(proof)) => self.validate_finality_proof(proof, sender), - Err(e) => { - debug!(target: LOG_TARGET, "Error decoding message: {}", e); - let bytes = raw.len().min(i32::MAX as usize) as i32; - let cost = ReputationChange::new( - bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), - "BEEFY: Bad packet", - ); - Action::Discard(cost) - }, - }; - match action { - Action::Keep(topic, cb) => { - self.report(*sender, cb); - context.broadcast_message(topic, data.to_vec(), false); - ValidationResult::ProcessAndKeep(topic) - }, - Action::Discard(cb) => { - self.report(*sender, cb); - ValidationResult::Discard - }, - Action::DiscardNoReport => ValidationResult::Discard, - } - } - - fn message_expired<'a>(&'a self) -> Box bool + 'a> { - let filter = self.gossip_filter.read(); - Box::new(move |_topic, mut data| match GossipMessage::::decode_all(&mut data) { - Ok(GossipMessage::Vote(msg)) => { - let round = msg.commitment.block_number; - let set_id = msg.commitment.validator_set_id; - let expired = filter.consider_vote(round, set_id) != Consider::Accept; - trace!(target: LOG_TARGET, "🥩 Vote for round #{} expired: {}", round, expired); - expired - }, - Ok(GossipMessage::FinalityProof(proof)) => { - let (round, set_id) = proof_block_num_and_set_id::(&proof); - let expired = filter.consider_finality_proof(round, set_id) != Consider::Accept; - trace!( - target: LOG_TARGET, - "🥩 Finality proof for round #{} expired: {}", - round, - expired - ); - expired - }, - Err(_) => true, - }) - } - - fn message_allowed<'a>( - &'a self, - ) -> Box bool + 'a> { - let do_rebroadcast = { - let now = Instant::now(); - let mut next_rebroadcast = self.next_rebroadcast.lock(); - if now >= *next_rebroadcast { - trace!(target: LOG_TARGET, "🥩 Gossip rebroadcast"); - *next_rebroadcast = now + REBROADCAST_AFTER; - true - } else { - false - } - }; - - let filter = self.gossip_filter.read(); - Box::new(move |_who, intent, _topic, mut data| { - if let MessageIntent::PeriodicRebroadcast = intent { - return do_rebroadcast; - } - - match GossipMessage::::decode_all(&mut data) { - Ok(GossipMessage::Vote(msg)) => { - let round = msg.commitment.block_number; - let set_id = msg.commitment.validator_set_id; - let allowed = filter.consider_vote(round, set_id) == Consider::Accept; - trace!(target: LOG_TARGET, "🥩 Vote for round #{} allowed: {}", round, allowed); - allowed - }, - Ok(GossipMessage::FinalityProof(proof)) => { - let (round, set_id) = proof_block_num_and_set_id::(&proof); - let allowed = filter.consider_finality_proof(round, set_id) == Consider::Accept; - trace!( - target: LOG_TARGET, - "🥩 Finality proof for round #{} allowed: {}", - round, - allowed - ); - allowed - }, - Err(_) => false, - } - }) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::keystore::BeefyKeystore; - use sc_network_test::Block; - use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; - use sp_consensus_beefy_etf::{ - bls_crypto::Signature, known_payloads, test_utils::Keyring, Commitment, MmrRootHash, - Payload, SignedCommitment, VoteMessage, - }; - use sp_keystore::{testing::MemoryKeystore, Keystore}; - - struct TestContext; - impl ValidatorContext for TestContext { - fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { - todo!() - } - - fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) {} - - fn send_message(&mut self, _who: &sc_network::PeerId, _message: Vec) { - todo!() - } - - fn send_topic(&mut self, _who: &sc_network::PeerId, _topic: B::Hash, _force: bool) { - todo!() - } - } - - pub fn sign_commitment( - who: &Keyring, - commitment: &Commitment, - ) -> Signature { - let store = MemoryKeystore::new(); - store.bls381_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store.into()).into(); - beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() - } - - fn dummy_vote(block_number: u64) -> VoteMessage { - let payload = Payload::from_single_entry( - known_payloads::MMR_ROOT_ID, - MmrRootHash::default().encode(), - ); - let commitment = Commitment { payload, block_number, validator_set_id: 0 }; - let signature = sign_commitment(&Keyring::Alice, &commitment); - - VoteMessage { commitment, id: Keyring::Alice.public(), signature } - } - - pub fn dummy_proof( - block_number: u64, - validator_set: &ValidatorSet, - ) -> BeefyVersionedFinalityProof { - let payload = Payload::from_single_entry( - known_payloads::MMR_ROOT_ID, - MmrRootHash::default().encode(), - ); - let commitment = Commitment { payload, block_number, validator_set_id: validator_set.id() }; - let signatures = validator_set - .validators() - .iter() - .map(|validator: &AuthorityId| { - Some(sign_commitment( - &Keyring::::from_public(validator).unwrap(), - &commitment, - )) - }) - .collect(); - - BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment, signatures }) - } - - #[test] - fn should_validate_messages() { - let keys = vec![Keyring::::Alice.public()]; - let validator_set = - ValidatorSet::::new(keys.clone(), keys.clone(), 0).unwrap(); - let (gv, mut report_stream) = - GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - let sender = PeerId::random(); - let mut context = TestContext; - - // reject message, decoding error - let bad_encoding = b"0000000000".as_slice(); - let expected_cost = ReputationChange::new( - (bad_encoding.len() as i32).saturating_mul(cost::PER_UNDECODABLE_BYTE), - "BEEFY: Bad packet", - ); - let mut expected_report = PeerReport { who: sender, cost_benefit: expected_cost }; - let res = gv.validate(&mut context, &sender, bad_encoding); - assert!(matches!(res, ValidationResult::Discard)); - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // verify votes validation - - let vote = dummy_vote(3); - let encoded = GossipMessage::::Vote(vote.clone()).encode(); - - // filter not initialized - let res = gv.validate(&mut context, &sender, &encoded); - assert!(matches!(res, ValidationResult::Discard)); - // nothing reported - assert!(report_stream.try_recv().is_err()); - - gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); - // nothing in cache first time - let res = gv.validate(&mut context, &sender, &encoded); - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - expected_report.cost_benefit = benefit::VOTE_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // reject vote, voter not in validator set - let mut bad_vote = vote.clone(); - bad_vote.id = Keyring::Bob.public(); - let bad_vote = GossipMessage::::Vote(bad_vote).encode(); - let res = gv.validate(&mut context, &sender, &bad_vote); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::UNKNOWN_VOTER; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // reject if the round is not GRANDPA finalized - gv.update_filter(GossipFilterCfg { start: 1, end: 2, validator_set: &validator_set }); - let number = vote.commitment.block_number; - let set_id = vote.commitment.validator_set_id; - assert_eq!(gv.gossip_filter.read().consider_vote(number, set_id), Consider::RejectFuture); - let res = gv.validate(&mut context, &sender, &encoded); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::FUTURE_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // reject if the round is not live anymore - gv.update_filter(GossipFilterCfg { start: 7, end: 10, validator_set: &validator_set }); - let number = vote.commitment.block_number; - let set_id = vote.commitment.validator_set_id; - assert_eq!(gv.gossip_filter.read().consider_vote(number, set_id), Consider::RejectPast); - let res = gv.validate(&mut context, &sender, &encoded); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::OUTDATED_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // now verify proofs validation - - // reject old proof - let proof = dummy_proof(5, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - let res = gv.validate(&mut context, &sender, &encoded_proof); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::OUTDATED_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // accept next proof with good set_id - let proof = dummy_proof(7, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - let res = gv.validate(&mut context, &sender, &encoded_proof); - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - expected_report.cost_benefit = benefit::VALIDATED_PROOF; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // accept future proof with good set_id - let proof = dummy_proof(20, &validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - let res = gv.validate(&mut context, &sender, &encoded_proof); - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - expected_report.cost_benefit = benefit::VALIDATED_PROOF; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // reject proof, future set_id - let bad_validator_set = ValidatorSet::::new(keys.clone(), keys, 1).unwrap(); - let proof = dummy_proof(20, &bad_validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - let res = gv.validate(&mut context, &sender, &encoded_proof); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::FUTURE_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - - // reject proof, bad signatures (Bob instead of Alice) - let bad_validator_set = ValidatorSet::::new( - vec![Keyring::Bob.public()], - vec![Keyring::Bob.public()], - 0, - ) - .unwrap(); - let proof = dummy_proof(21, &bad_validator_set); - let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - let res = gv.validate(&mut context, &sender, &encoded_proof); - assert!(matches!(res, ValidationResult::Discard)); - expected_report.cost_benefit = cost::INVALID_PROOF; - expected_report.cost_benefit.value += cost::PER_SIGNATURE_CHECKED; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); - } - - #[test] - fn messages_allowed_and_expired() { - let keys = vec![Keyring::Alice.public()]; - let validator_set = - ValidatorSet::::new(keys.clone(), keys.clone(), 0).unwrap(); - let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); - let sender = sc_network::PeerId::random(); - let topic = Default::default(); - let intent = MessageIntent::Broadcast; - - // conclude 2 - gv.update_filter(GossipFilterCfg { start: 2, end: 10, validator_set: &validator_set }); - let mut allowed = gv.message_allowed(); - let mut expired = gv.message_expired(); - - // check bad vote format - assert!(!allowed(&sender, intent, &topic, &mut [0u8; 16])); - assert!(expired(topic, &mut [0u8; 16])); - - // inactive round 1 -> expired - let vote = dummy_vote(1); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); - assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); - assert!(expired(topic, &mut encoded_vote)); - let proof = dummy_proof(1, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(expired(topic, &mut encoded_proof)); - - // active round 2 -> !expired - concluded but still gossiped - let vote = dummy_vote(2); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); - assert!(!expired(topic, &mut encoded_vote)); - let proof = dummy_proof(2, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(!expired(topic, &mut encoded_proof)); - // using wrong set_id -> !allowed, expired - let bad_validator_set = - ValidatorSet::::new(keys.clone(), keys.clone(), 1).unwrap(); - let proof = dummy_proof(2, &bad_validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(expired(topic, &mut encoded_proof)); - - // in progress round 3 -> !expired - let vote = dummy_vote(3); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); - assert!(!expired(topic, &mut encoded_vote)); - let proof = dummy_proof(3, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(!expired(topic, &mut encoded_proof)); - - // unseen round 4 -> !expired - let vote = dummy_vote(4); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); - assert!(!expired(topic, &mut encoded_vote)); - let proof = dummy_proof(4, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(!expired(topic, &mut encoded_proof)); - - // future round 11 -> expired - let vote = dummy_vote(11); - let mut encoded_vote = GossipMessage::::Vote(vote).encode(); - assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); - assert!(expired(topic, &mut encoded_vote)); - // future proofs allowed while same set_id -> allowed - let proof = dummy_proof(11, &validator_set); - let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); - assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); - assert!(!expired(topic, &mut encoded_proof)); - } - - #[test] - fn messages_rebroadcast() { - let keys = vec![Keyring::Alice.public()]; - let validator_set = - ValidatorSet::::new(keys.clone(), keys.clone(), 0).unwrap(); - let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); - let sender = sc_network::PeerId::random(); - let topic = Default::default(); - - let vote = dummy_vote(1); - let mut encoded_vote = vote.encode(); - - // re-broadcasting only allowed at `REBROADCAST_AFTER` intervals - let intent = MessageIntent::PeriodicRebroadcast; - let mut allowed = gv.message_allowed(); - - // rebroadcast not allowed so soon after GossipValidator creation - assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); - - // hack the inner deadline to be `now` - *gv.next_rebroadcast.lock() = Instant::now(); - - // still not allowed on old `allowed` closure result - assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); - - // renew closure result - let mut allowed = gv.message_allowed(); - // rebroadcast should be allowed now - assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); - } -} diff --git a/client/consensus/beefy-etf/src/communication/mod.rs b/client/consensus/beefy-etf/src/communication/mod.rs deleted file mode 100644 index 3c93368..0000000 --- a/client/consensus/beefy-etf/src/communication/mod.rs +++ /dev/null @@ -1,160 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Communication streams for the BEEFY networking protocols. - -pub mod notification; -pub mod request_response; - -pub(crate) mod gossip; -pub(crate) mod peers; - -pub(crate) mod beefy_protocol_name { - use array_bytes::bytes2hex; - use sc_network::ProtocolName; - - /// BEEFY votes gossip protocol name suffix. - const GOSSIP_NAME: &str = "/beefy/2"; - /// BEEFY justifications protocol name suffix. - const JUSTIFICATIONS_NAME: &str = "/beefy/justifications/1"; - - /// Name of the votes gossip protocol used by BEEFY. - /// - /// Must be registered towards the networking in order for BEEFY voter to properly function. - pub fn gossip_protocol_name>( - genesis_hash: Hash, - fork_id: Option<&str>, - ) -> ProtocolName { - let genesis_hash = genesis_hash.as_ref(); - if let Some(fork_id) = fork_id { - format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, GOSSIP_NAME).into() - } else { - format!("/{}{}", bytes2hex("", genesis_hash), GOSSIP_NAME).into() - } - } - - /// Name of the BEEFY justifications request-response protocol. - pub fn justifications_protocol_name>( - genesis_hash: Hash, - fork_id: Option<&str>, - ) -> ProtocolName { - let genesis_hash = genesis_hash.as_ref(); - if let Some(fork_id) = fork_id { - format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, JUSTIFICATIONS_NAME).into() - } else { - format!("/{}{}", bytes2hex("", genesis_hash), JUSTIFICATIONS_NAME).into() - } - } -} - -/// Returns the configuration value to put in -/// [`sc_network::config::FullNetworkConfiguration`]. -/// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. -pub fn beefy_peers_set_config< - B: sp_runtime::traits::Block, - N: sc_network::NetworkBackend::Hash>, ->( - gossip_protocol_name: sc_network::ProtocolName, - metrics: sc_network::service::NotificationMetrics, - peer_store_handle: std::sync::Arc, -) -> (N::NotificationProtocolConfig, Box) { - let (cfg, notification_service) = N::notification_config( - gossip_protocol_name, - Vec::new(), - 1024 * 1024, - None, - sc_network::config::SetConfig { - in_peers: 25, - out_peers: 25, - reserved_nodes: Vec::new(), - non_reserved_mode: sc_network::config::NonReservedPeerMode::Accept, - }, - metrics, - peer_store_handle, - ); - (cfg, notification_service) -} - -// cost scalars for reporting peers. -mod cost { - use sc_network::ReputationChange as Rep; - // Message that's for an outdated round. - pub(super) const OUTDATED_MESSAGE: Rep = Rep::new(-50, "BEEFY: Past message"); - // Message that's from the future relative to our current set-id. - pub(super) const FUTURE_MESSAGE: Rep = Rep::new(-100, "BEEFY: Future message"); - // Vote message containing bad signature. - pub(super) const BAD_SIGNATURE: Rep = Rep::new(-100, "BEEFY: Bad signature"); - // Message received with vote from voter not in validator set. - pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "BEEFY: Unknown voter"); - // Message containing invalid proof. - pub(super) const INVALID_PROOF: Rep = Rep::new(-5000, "BEEFY: Invalid commit"); - // Reputation cost per signature checked for invalid proof. - pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; - // Reputation cost per byte for un-decodable message. - pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; - // On-demand request was refused by peer. - pub(super) const REFUSAL_RESPONSE: Rep = Rep::new(-100, "BEEFY: Proof request refused"); - // On-demand request for a proof that can't be found in the backend. - pub(super) const UNKNOWN_PROOF_REQUEST: Rep = Rep::new(-150, "BEEFY: Unknown proof request"); -} - -// benefit scalars for reporting peers. -mod benefit { - use sc_network::ReputationChange as Rep; - pub(super) const VOTE_MESSAGE: Rep = Rep::new(100, "BEEFY: Round vote message"); - pub(super) const NOT_INTERESTED: Rep = Rep::new(10, "BEEFY: Not interested in round"); - pub(super) const VALIDATED_PROOF: Rep = Rep::new(100, "BEEFY: Justification"); -} - -#[cfg(test)] -mod tests { - use super::*; - - use sp_core::H256; - - #[test] - fn beefy_protocols_names() { - use beefy_protocol_name::{gossip_protocol_name, justifications_protocol_name}; - // Create protocol name using random genesis hash. - let genesis_hash = H256::random(); - let genesis_hex = array_bytes::bytes2hex("", genesis_hash); - - let expected_gossip_name = format!("/{}/beefy/2", genesis_hex); - let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); - assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); - - let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); - let justif_proto_name = justifications_protocol_name(&genesis_hash, None); - assert_eq!(justif_proto_name.to_string(), expected_justif_name); - - // Create protocol name using hardcoded genesis hash. Verify exact representation. - let genesis_hash = [ - 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, - 94, 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, - ]; - let genesis_hex = "32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93"; - - let expected_gossip_name = format!("/{}/beefy/2", genesis_hex); - let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); - assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); - - let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); - let justif_proto_name = justifications_protocol_name(&genesis_hash, None); - assert_eq!(justif_proto_name.to_string(), expected_justif_name); - } -} diff --git a/client/consensus/beefy-etf/src/communication/notification.rs b/client/consensus/beefy-etf/src/communication/notification.rs deleted file mode 100644 index a4486e5..0000000 --- a/client/consensus/beefy-etf/src/communication/notification.rs +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr}; -use sp_runtime::traits::Block as BlockT; - -use crate::justification::BeefyVersionedFinalityProof; - -/// The sending half of the notifications channel(s) used to send -/// notifications about best BEEFY block from the gadget side. -pub type BeefyBestBlockSender = NotificationSender<::Hash>; - -/// The receiving half of a notifications channel used to receive -/// notifications about best BEEFY blocks determined on the gadget side. -pub type BeefyBestBlockStream = - NotificationStream<::Hash, BeefyBestBlockTracingKey>; - -/// 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>; - -/// 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>; - -/// Provides tracing key for BEEFY best block stream. -#[derive(Clone)] -pub struct BeefyBestBlockTracingKey; -impl TracingKeyStr for BeefyBestBlockTracingKey { - const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream"; -} - -/// Provides tracing key for BEEFY versioned finality proof stream. -#[derive(Clone)] -pub struct BeefyVersionedFinalityProofTracingKey; -impl TracingKeyStr for BeefyVersionedFinalityProofTracingKey { - const TRACING_KEY: &'static str = "mpsc_beefy_versioned_finality_proof_notification_stream"; -} diff --git a/client/consensus/beefy-etf/src/communication/peers.rs b/client/consensus/beefy-etf/src/communication/peers.rs deleted file mode 100644 index 8f2d5cc..0000000 --- a/client/consensus/beefy-etf/src/communication/peers.rs +++ /dev/null @@ -1,127 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Logic for keeping track of BEEFY peers. - -use sc_network::{PeerId, ReputationChange}; -use sp_runtime::traits::{Block, NumberFor, Zero}; -use std::collections::{HashMap, VecDeque}; - -/// Report specifying a reputation change for a given peer. -#[derive(Debug, PartialEq)] -pub struct PeerReport { - pub who: PeerId, - pub cost_benefit: ReputationChange, -} - -struct PeerData { - last_voted_on: NumberFor, -} - -impl Default for PeerData { - fn default() -> Self { - PeerData { last_voted_on: Zero::zero() } - } -} - -/// Keep a simple map of connected peers -/// and the most recent voting round they participated in. -pub struct KnownPeers { - live: HashMap>, -} - -impl KnownPeers { - pub fn new() -> Self { - Self { live: HashMap::new() } - } - - /// Note vote round number for `peer`. - pub fn note_vote_for(&mut self, peer: PeerId, round: NumberFor) { - let data = self.live.entry(peer).or_default(); - data.last_voted_on = round.max(data.last_voted_on); - } - - /// Remove connected `peer`. - pub fn remove(&mut self, peer: &PeerId) { - self.live.remove(peer); - } - - /// Return _filtered and cloned_ list of peers that have voted on higher than `block`. - pub fn further_than(&self, block: NumberFor) -> VecDeque { - self.live - .iter() - .filter_map(|(k, v)| (v.last_voted_on > block).then_some(k)) - .cloned() - .collect() - } - - /// Answer whether `peer` is part of `KnownPeers` set. - pub fn contains(&self, peer: &PeerId) -> bool { - self.live.contains_key(peer) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn should_track_known_peers_progress() { - let (alice, bob, charlie) = (PeerId::random(), PeerId::random(), PeerId::random()); - let mut peers = KnownPeers::::new(); - assert!(peers.live.is_empty()); - - // 'Tracked' Bob seen voting for 5. - peers.note_vote_for(bob, 5); - // Previously unseen Charlie now seen voting for 10. - peers.note_vote_for(charlie, 10); - - assert_eq!(peers.live.len(), 2); - assert!(!peers.contains(&alice)); - assert!(peers.contains(&bob)); - assert!(peers.contains(&charlie)); - - // Get peers at block > 4 - let further_than_4 = peers.further_than(4); - // Should be Bob and Charlie - assert_eq!(further_than_4.len(), 2); - assert!(further_than_4.contains(&bob)); - assert!(further_than_4.contains(&charlie)); - - // 'Tracked' Alice seen voting for 10. - peers.note_vote_for(alice, 10); - - // Get peers at block > 9 - let further_than_9 = peers.further_than(9); - // Should be Charlie and Alice - assert_eq!(further_than_9.len(), 2); - assert!(further_than_9.contains(&charlie)); - assert!(further_than_9.contains(&alice)); - - // Remove Alice - peers.remove(&alice); - assert_eq!(peers.live.len(), 2); - assert!(!peers.contains(&alice)); - - // Get peers at block >= 9 - let further_than_9 = peers.further_than(9); - // Now should be just Charlie - assert_eq!(further_than_9.len(), 1); - assert!(further_than_9.contains(&charlie)); - } -} diff --git a/client/consensus/beefy-etf/src/communication/request_response/incoming_requests_handler.rs b/client/consensus/beefy-etf/src/communication/request_response/incoming_requests_handler.rs deleted file mode 100644 index 6f489a6..0000000 --- a/client/consensus/beefy-etf/src/communication/request_response/incoming_requests_handler.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Helper for handling (i.e. answering) BEEFY justifications requests from a remote peer. - -use codec::DecodeAll; -use futures::{channel::oneshot, StreamExt}; -use log::{debug, trace}; -use sc_client_api::BlockBackend; -use sc_network::{ - config as netconfig, service::traits::RequestResponseConfig, types::ProtocolName, - NetworkBackend, ReputationChange, -}; -use sc_network_types::PeerId; -use sp_consensus_beefy_etf::BEEFY_ENGINE_ID; -use sp_runtime::traits::Block; -use std::{marker::PhantomData, sync::Arc}; - -use crate::{ - communication::{ - cost, - request_response::{ - on_demand_justifications_protocol_config, Error, JustificationRequest, - BEEFY_SYNC_LOG_TARGET, - }, - }, - metric_inc, - metrics::{register_metrics, OnDemandIncomingRequestsMetrics}, -}; - -/// A request coming in, including a sender for sending responses. -#[derive(Debug)] -pub(crate) struct IncomingRequest { - /// `PeerId` of sending peer. - pub peer: PeerId, - /// The sent request. - pub payload: JustificationRequest, - /// Sender for sending response back. - pub pending_response: oneshot::Sender, -} - -impl IncomingRequest { - /// Create new `IncomingRequest`. - pub fn new( - peer: PeerId, - payload: JustificationRequest, - pending_response: oneshot::Sender, - ) -> Self { - Self { peer, payload, pending_response } - } - - /// Try building from raw network request. - /// - /// This function will fail if the request cannot be decoded and will apply passed in - /// reputation changes in that case. - /// - /// Params: - /// - The raw request to decode - /// - Reputation changes to apply for the peer in case decoding fails. - pub fn try_from_raw( - raw: netconfig::IncomingRequest, - reputation_changes_on_err: F, - ) -> Result - where - F: FnOnce(usize) -> Vec, - { - let netconfig::IncomingRequest { payload, peer, pending_response } = raw; - let payload = match JustificationRequest::decode_all(&mut payload.as_ref()) { - Ok(payload) => payload, - Err(err) => { - let response = netconfig::OutgoingResponse { - result: Err(()), - reputation_changes: reputation_changes_on_err(payload.len()), - sent_feedback: None, - }; - if let Err(_) = pending_response.send(response) { - return Err(Error::DecodingErrorNoReputationChange(peer, err)); - } - return Err(Error::DecodingError(peer, err)); - }, - }; - Ok(Self::new(peer, payload, pending_response)) - } -} - -/// Receiver for incoming BEEFY justifications requests. -/// -/// Takes care of decoding and handling of invalid encoded requests. -pub(crate) struct IncomingRequestReceiver { - raw: async_channel::Receiver, -} - -impl IncomingRequestReceiver { - pub fn new(inner: async_channel::Receiver) -> Self { - Self { raw: inner } - } - - /// Try to receive the next incoming request. - /// - /// Any received request will be decoded, on decoding errors the provided reputation changes - /// will be applied and an error will be reported. - pub async fn recv(&mut self, reputation_changes: F) -> Result, Error> - where - B: Block, - F: FnOnce(usize) -> Vec, - { - let req = match self.raw.next().await { - None => return Err(Error::RequestChannelExhausted), - Some(raw) => IncomingRequest::::try_from_raw(raw, reputation_changes)?, - }; - Ok(req) - } -} - -/// Handler for incoming BEEFY justifications requests from a remote peer. -pub struct BeefyJustifsRequestHandler { - pub(crate) request_receiver: IncomingRequestReceiver, - pub(crate) justif_protocol_name: ProtocolName, - pub(crate) client: Arc, - pub(crate) metrics: Option, - pub(crate) _block: PhantomData, -} - -impl BeefyJustifsRequestHandler -where - B: Block, - Client: BlockBackend + Send + Sync, -{ - /// Create a new [`BeefyJustifsRequestHandler`]. - pub fn new, Network: NetworkBackend::Hash>>( - genesis_hash: Hash, - fork_id: Option<&str>, - client: Arc, - prometheus_registry: Option, - ) -> (Self, Network::RequestResponseProtocolConfig) { - let (request_receiver, config): (_, Network::RequestResponseProtocolConfig) = - on_demand_justifications_protocol_config::(genesis_hash, fork_id); - let justif_protocol_name = config.protocol_name().clone(); - let metrics = register_metrics(prometheus_registry); - ( - Self { request_receiver, justif_protocol_name, client, metrics, _block: PhantomData }, - config, - ) - } - - /// Network request-response protocol name used by this handler. - pub fn protocol_name(&self) -> ProtocolName { - self.justif_protocol_name.clone() - } - - // Sends back justification response if justification found in client backend. - fn handle_request(&self, request: IncomingRequest) -> Result<(), Error> { - let mut reputation_changes = vec![]; - let maybe_encoded_proof = self - .client - .block_hash(request.payload.begin) - .ok() - .flatten() - .and_then(|hash| self.client.justifications(hash).ok().flatten()) - .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) - .ok_or_else(|| reputation_changes.push(cost::UNKNOWN_PROOF_REQUEST)); - request - .pending_response - .send(netconfig::OutgoingResponse { - result: maybe_encoded_proof, - reputation_changes, - sent_feedback: None, - }) - .map_err(|_| Error::SendResponse) - } - - /// Run [`BeefyJustifsRequestHandler`]. - /// - /// Should never end, returns `Error` otherwise. - pub async fn run(&mut self) -> Error { - trace!(target: BEEFY_SYNC_LOG_TARGET, "🥩 Running BeefyJustifsRequestHandler"); - - while let Ok(request) = self - .request_receiver - .recv(|bytes| { - let bytes = bytes.min(i32::MAX as usize) as i32; - vec![ReputationChange::new( - bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), - "BEEFY: Bad request payload", - )] - }) - .await - { - let peer = request.peer; - match self.handle_request(request) { - Ok(()) => { - metric_inc!(self.metrics, beefy_successful_justification_responses); - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 Handled BEEFY justification request from {:?}.", peer - ) - }, - Err(e) => { - // peer reputation changes already applied in `self.handle_request()` - metric_inc!(self.metrics, beefy_failed_justification_responses); - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 Failed to handle BEEFY justification request from {:?}: {}", peer, e, - ) - }, - } - } - Error::RequestsReceiverStreamClosed - } -} diff --git a/client/consensus/beefy-etf/src/communication/request_response/mod.rs b/client/consensus/beefy-etf/src/communication/request_response/mod.rs deleted file mode 100644 index 63cabb3..0000000 --- a/client/consensus/beefy-etf/src/communication/request_response/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Request/response protocol for syncing BEEFY justifications. - -mod incoming_requests_handler; -pub(crate) mod outgoing_requests_engine; - -pub use incoming_requests_handler::BeefyJustifsRequestHandler; - -use std::time::Duration; - -use codec::{Decode, Encode, Error as CodecError}; -// use sc_network::Config::RequestResponseConfig; -use sc_network::NetworkBackend; -use sc_network_types::PeerId; -use sp_runtime::traits::{Block, NumberFor}; - -use crate::communication::{beefy_protocol_name::justifications_protocol_name, peers::PeerReport}; -use incoming_requests_handler::IncomingRequestReceiver; - -// 10 seems reasonable, considering justifs are explicitly requested only -// for mandatory blocks, by nodes that are syncing/catching-up. -const JUSTIF_CHANNEL_SIZE: usize = 10; - -const MAX_RESPONSE_SIZE: u64 = 1024 * 1024; -const JUSTIF_REQUEST_TIMEOUT: Duration = Duration::from_secs(3); - -const BEEFY_SYNC_LOG_TARGET: &str = "beefy::sync"; - -/// Get the configuration for the BEEFY justifications Request/response protocol. -/// -/// Returns a receiver for messages received on this protocol and the requested -/// `ProtocolConfig`. -/// -/// Consider using [`BeefyJustifsRequestHandler`] instead of this low-level function. -pub(crate) fn on_demand_justifications_protocol_config< - Hash: AsRef<[u8]>, - B: Block, - Network: NetworkBackend::Hash>, ->( - genesis_hash: Hash, - fork_id: Option<&str>, -) -> (IncomingRequestReceiver, Network::RequestResponseProtocolConfig) { - let name = justifications_protocol_name(genesis_hash, fork_id); - let fallback_names = vec![]; - let (tx, rx) = async_channel::bounded(JUSTIF_CHANNEL_SIZE); - let rx = IncomingRequestReceiver::new(rx); - let cfg = Network::request_response_config( - name, - fallback_names, - 32, - MAX_RESPONSE_SIZE, - // We are connected to all validators: - JUSTIF_REQUEST_TIMEOUT, - Some(tx), - ); - (rx, cfg) -} - -/// BEEFY justification request. -#[derive(Debug, Clone, Encode, Decode)] -pub struct JustificationRequest { - /// Start collecting proofs from this block. - pub begin: NumberFor, -} - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error(transparent)] - Client(#[from] sp_blockchain::Error), - - #[error(transparent)] - RuntimeApi(#[from] sp_api::ApiError), - - /// Decoding failed, we were able to change the peer's reputation accordingly. - #[error("Decoding request failed for peer {0}.")] - DecodingError(PeerId, #[source] CodecError), - - /// Decoding failed, but sending reputation change failed. - #[error("Decoding request failed for peer {0}, and changing reputation failed.")] - DecodingErrorNoReputationChange(PeerId, #[source] CodecError), - - /// Incoming request stream exhausted. Should only happen on shutdown. - #[error("Incoming request channel got closed.")] - RequestChannelExhausted, - - #[error("Failed to send response.")] - SendResponse, - - #[error("Received invalid response.")] - InvalidResponse(PeerReport), - - #[error("Internal error while getting response.")] - ResponseError, - - #[error("On-demand requests receiver stream terminated.")] - RequestsReceiverStreamClosed, -} diff --git a/client/consensus/beefy-etf/src/communication/request_response/outgoing_requests_engine.rs b/client/consensus/beefy-etf/src/communication/request_response/outgoing_requests_engine.rs deleted file mode 100644 index 910054d..0000000 --- a/client/consensus/beefy-etf/src/communication/request_response/outgoing_requests_engine.rs +++ /dev/null @@ -1,280 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Generating request logic for request/response protocol for syncing BEEFY justifications. - -use codec::Encode; -use futures::channel::{oneshot, oneshot::Canceled}; -use log::{debug, warn}; -use parking_lot::Mutex; -use sc_network::{ - request_responses::{IfDisconnected, RequestFailure}, - NetworkRequest, PeerId, ProtocolName, -}; - -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::{bls_crypto::AuthorityId, ValidatorSet}; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::{ecdsa_crypto::AuthorityId, ValidatorSet}; - -use sp_runtime::traits::{Block, NumberFor}; -use std::{collections::VecDeque, result::Result, sync::Arc}; - -use crate::{ - communication::{ - benefit, cost, - peers::PeerReport, - request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, - }, - justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, - metric_inc, - metrics::{register_metrics, OnDemandOutgoingRequestsMetrics}, - KnownPeers, -}; - -/// Response type received from network. -type Response = Result<(Vec, ProtocolName), RequestFailure>; -/// Used to receive a response from the network. -type ResponseReceiver = oneshot::Receiver; - -#[derive(Clone, Debug)] -struct RequestInfo { - block: NumberFor, - active_set: ValidatorSet, -} - -enum State { - Idle, - AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), -} - -/// Possible engine responses. -pub(crate) enum ResponseInfo { - /// No peer response available yet. - Pending, - /// Valid justification provided alongside peer reputation changes. - ValidProof(BeefyVersionedFinalityProof, PeerReport), - /// No justification yet, only peer reputation changes. - PeerReport(PeerReport), -} - -pub struct OnDemandJustificationsEngine { - network: Arc, - protocol_name: ProtocolName, - - live_peers: Arc>>, - peers_cache: VecDeque, - - state: State, - metrics: Option, -} - -impl OnDemandJustificationsEngine { - pub fn new( - network: Arc, - protocol_name: ProtocolName, - live_peers: Arc>>, - prometheus_registry: Option, - ) -> Self { - let metrics = register_metrics(prometheus_registry); - Self { - network, - protocol_name, - live_peers, - peers_cache: VecDeque::new(), - state: State::Idle, - metrics, - } - } - - fn reset_peers_cache_for_block(&mut self, block: NumberFor) { - self.peers_cache = self.live_peers.lock().further_than(block); - } - - fn try_next_peer(&mut self) -> Option { - let live = self.live_peers.lock(); - while let Some(peer) = self.peers_cache.pop_front() { - if live.contains(&peer) { - return Some(peer); - } - } - None - } - - 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, - ); - - let payload = JustificationRequest:: { begin: req_info.block }.encode(); - - let (tx, rx) = oneshot::channel(); - - self.network.start_request( - peer, - self.protocol_name.clone(), - payload, - None, - tx, - IfDisconnected::ImmediateError, - ); - - self.state = State::AwaitingResponse(peer, req_info, rx); - } - - /// 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) { - // ignore new requests while there's already one pending - if matches!(self.state, State::AwaitingResponse(_, _, _)) { - return; - } - self.reset_peers_cache_for_block(block); - - // Start the requests engine - each unsuccessful received response will automatically - // trigger a new request to the next peer in the `peers_cache` until there are none left. - if let Some(peer) = self.try_next_peer() { - self.request_from_peer(peer, RequestInfo { block, active_set }); - } else { - metric_inc!(self.metrics, beefy_on_demand_justification_no_peer_to_request_from); - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 no good peers to request justif #{:?} from", block - ); - } - } - - /// Cancel any pending request for block numbers smaller or equal to `block`. - pub fn cancel_requests_older_than(&mut self, block: NumberFor) { - match &self.state { - State::AwaitingResponse(_, req_info, _) if req_info.block <= block => { - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 cancel pending request for justification #{:?}", req_info.block - ); - self.state = State::Idle; - }, - _ => (), - } - } - - fn process_response( - &mut self, - peer: &PeerId, - req_info: &RequestInfo, - response: Result, - ) -> Result, Error> { - response - .map_err(|e| { - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 on-demand sc-network channel sender closed, err: {:?}", e - ); - Error::ResponseError - })? - .map_err(|e| { - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", - req_info.block, - peer, - e - ); - match e { - RequestFailure::Refused => { - metric_inc!(self.metrics, beefy_on_demand_justification_peer_refused); - let peer_report = - PeerReport { who: *peer, cost_benefit: cost::REFUSAL_RESPONSE }; - Error::InvalidResponse(peer_report) - }, - _ => { - metric_inc!(self.metrics, beefy_on_demand_justification_peer_error); - Error::ResponseError - }, - } - }) - .and_then(|(encoded, _)| { - decode_and_verify_finality_proof::( - &encoded[..], - req_info.block, - &req_info.active_set, - ) - .map_err(|(err, signatures_checked)| { - metric_inc!(self.metrics, beefy_on_demand_justification_invalid_proof); - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", - req_info.block, peer, err - ); - let mut cost = cost::INVALID_PROOF; - cost.value += - cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); - Error::InvalidResponse(PeerReport { who: *peer, cost_benefit: cost }) - }) - }) - } - - pub(crate) async fn next(&mut self) -> ResponseInfo { - let (peer, req_info, resp) = match &mut self.state { - State::Idle => { - futures::future::pending::<()>().await; - return ResponseInfo::Pending; - }, - State::AwaitingResponse(peer, req_info, receiver) => { - let resp = receiver.await; - (*peer, req_info.clone(), resp) - }, - }; - // We received the awaited response. Our 'receiver' will never generate any other response, - // meaning we're done with current state. Move the engine to `State::Idle`. - self.state = State::Idle; - - let block = req_info.block; - match self.process_response(&peer, &req_info, resp) { - Err(err) => { - // No valid justification received, try next peer in our set. - if let Some(peer) = self.try_next_peer() { - self.request_from_peer(peer, req_info); - } else { - warn!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 ran out of peers to request justif #{:?} from", block - ); - } - // Report peer based on error type. - if let Error::InvalidResponse(peer_report) = err { - ResponseInfo::PeerReport(peer_report) - } else { - ResponseInfo::Pending - } - }, - Ok(proof) => { - metric_inc!(self.metrics, beefy_on_demand_justification_good_proof); - debug!( - target: BEEFY_SYNC_LOG_TARGET, - "🥩 received valid on-demand justif #{:?} from {:?}", block, peer - ); - let peer_report = PeerReport { who: peer, cost_benefit: benefit::VALIDATED_PROOF }; - ResponseInfo::ValidProof(proof, peer_report) - }, - } - } -} diff --git a/client/consensus/beefy-etf/src/error.rs b/client/consensus/beefy-etf/src/error.rs deleted file mode 100644 index b4773f9..0000000 --- a/client/consensus/beefy-etf/src/error.rs +++ /dev/null @@ -1,64 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! BEEFY gadget specific errors -//! -//! Used for BEEFY gadget internal error handling only - -use std::fmt::Debug; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Backend: {0}")] - Backend(String), - #[error("Keystore error: {0}")] - Keystore(String), - #[error("Runtime api error: {0}")] - RuntimeApi(sp_api::ApiError), - #[error("Signature error: {0}")] - Signature(String), - #[error("Session uninitialized")] - UninitSession, - #[error("pallet-beefy was reset")] - ConsensusReset, - #[error("Block import stream terminated")] - BlockImportStreamTerminated, - #[error("Gossip Engine terminated")] - GossipEngineTerminated, - #[error("Finality proofs gossiping stream terminated")] - FinalityProofGossipStreamTerminated, - #[error("Finality stream terminated")] - FinalityStreamTerminated, - #[error("Votes gossiping stream terminated")] - VotesGossipStreamTerminated, -} - -#[cfg(test)] -impl PartialEq for Error { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Error::Backend(s1), Error::Backend(s2)) => s1 == s2, - (Error::Keystore(s1), Error::Keystore(s2)) => s1 == s2, - (Error::RuntimeApi(_), Error::RuntimeApi(_)) => true, - (Error::Signature(s1), Error::Signature(s2)) => s1 == s2, - (Error::UninitSession, Error::UninitSession) => true, - (Error::ConsensusReset, Error::ConsensusReset) => true, - _ => false, - } - } -} diff --git a/client/consensus/beefy-etf/src/import.rs b/client/consensus/beefy-etf/src/import.rs deleted file mode 100644 index b76c7a4..0000000 --- a/client/consensus/beefy-etf/src/import.rs +++ /dev/null @@ -1,200 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use std::sync::Arc; - -use log::debug; - -use sp_api::ProvideRuntimeApi; -use sp_consensus::Error as ConsensusError; - -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::AuthorityId; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::ecdsa_crypto::AuthorityId; - -use sp_consensus_beefy_etf::{BeefyApi, BEEFY_ENGINE_ID}; -use sp_runtime::{ - traits::{Block as BlockT, Header as HeaderT, NumberFor}, - EncodedJustification, -}; - -use sc_client_api::backend::Backend; -use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult}; - -use crate::{ - communication::notification::BeefyVersionedFinalityProofSender, - justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, - metric_inc, - metrics::BlockImportMetrics, - LOG_TARGET, -}; - -/// A block-import handler for BEEFY. -/// -/// This scans each imported block for BEEFY justifications and verifies them. -/// 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 { - backend: Arc, - runtime: Arc, - inner: I, - justification_sender: BeefyVersionedFinalityProofSender, - metrics: Option, -} - -impl 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(), - metrics: self.metrics.clone(), - } - } -} - -impl BeefyBlockImport { - /// Create a new BeefyBlockImport. - pub fn new( - backend: Arc, - runtime: Arc, - inner: I, - justification_sender: BeefyVersionedFinalityProofSender, - metrics: Option, - ) -> BeefyBlockImport { - BeefyBlockImport { backend, runtime, inner, justification_sender, metrics } - } -} - -impl BeefyBlockImport -where - Block: BlockT, - BE: Backend, - Runtime: ProvideRuntimeApi, - Runtime::Api: BeefyApi + Send, -{ - fn decode_and_verify( - &self, - encoded: &EncodedJustification, - number: NumberFor, - hash: ::Hash, - ) -> Result, ConsensusError> { - use ConsensusError::ClientImport as ImportError; - let beefy_genesis = self - .runtime - .runtime_api() - .beefy_genesis(hash) - .map_err(|e| ImportError(e.to_string()))? - .ok_or_else(|| ImportError("Unknown BEEFY genesis".to_string()))?; - if number < beefy_genesis { - return Err(ImportError("BEEFY genesis is set for future block".to_string())); - } - let validator_set = self - .runtime - .runtime_api() - .validator_set(hash) - .map_err(|e| ImportError(e.to_string()))? - .ok_or_else(|| ImportError("Unknown validator set".to_string()))?; - - decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) - .map_err(|(err, _)| err) - } -} - -#[async_trait::async_trait] -impl BlockImport for BeefyBlockImport -where - Block: BlockT, - BE: Backend, - I: BlockImport + Send + Sync, - Runtime: ProvideRuntimeApi + Send + Sync, - Runtime::Api: BeefyApi, -{ - type Error = ConsensusError; - - async fn import_block( - &mut self, - mut block: BlockImportParams, - ) -> Result { - let hash = block.post_hash(); - let number = *block.header.number(); - - let beefy_encoded = block.justifications.as_mut().and_then(|just| { - let encoded = just.get(BEEFY_ENGINE_ID).cloned(); - // Remove BEEFY justification from the list before giving to `inner`; we send it to the - // voter (beefy-gadget) and it will append it to the backend after block is finalized. - just.remove(BEEFY_ENGINE_ID); - encoded - }); - - // Run inner block import. - let inner_import_result = self.inner.import_block(block).await?; - - match self.backend.state_at(hash) { - Ok(_) => {}, - Err(_) => { - // The block is imported as part of some chain sync. - // The voter doesn't need to process it now. - // It will be detected and processed as part of the voter state init. - return Ok(inner_import_result); - }, - } - - match (beefy_encoded, &inner_import_result) { - (Some(encoded), ImportResult::Imported(_)) => { - match self.decode_and_verify(&encoded, number, hash) { - Ok(proof) => { - // The proof is valid and the block is imported and final, we can import. - debug!( - target: LOG_TARGET, - "🥩 import justif {} for block number {:?}.", proof, number - ); - // Send the justification to the BEEFY voter for processing. - self.justification_sender - .notify(|| Ok::<_, ()>(proof)) - .expect("the closure always returns Ok; qed."); - metric_inc!(self.metrics, beefy_good_justification_imports); - }, - Err(err) => { - debug!( - target: LOG_TARGET, - "🥩 error importing BEEFY justification for block {:?}: {:?}", - number, - err, - ); - metric_inc!(self.metrics, beefy_bad_justification_imports); - }, - } - }, - _ => (), - } - - Ok(inner_import_result) - } - - async fn check_block( - &mut self, - block: BlockCheckParams, - ) -> Result { - self.inner.check_block(block).await - } -} diff --git a/client/consensus/beefy-etf/src/justification.rs b/client/consensus/beefy-etf/src/justification.rs deleted file mode 100644 index 7704052..0000000 --- a/client/consensus/beefy-etf/src/justification.rs +++ /dev/null @@ -1,251 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::keystore::BeefyKeystore; -use codec::{DecodeAll, Encode}; -use sp_consensus::Error as ConsensusError; - -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::{AuthorityId, Signature}; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::ecdsa_crypto::{AuthorityId, Signature}; - -use sp_consensus_beefy_etf::{ValidatorSet, ValidatorSetId, VersionedFinalityProof}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; - -/// A finality proof with matching BEEFY authorities' signatures. -pub type BeefyVersionedFinalityProof = VersionedFinalityProof, Signature>; - -pub(crate) fn proof_block_num_and_set_id( - proof: &BeefyVersionedFinalityProof, -) -> (NumberFor, ValidatorSetId) { - match proof { - VersionedFinalityProof::V1(sc) => - (sc.commitment.block_number, sc.commitment.validator_set_id), - } -} - -/// Decode and verify a Beefy FinalityProof. -pub(crate) fn decode_and_verify_finality_proof( - encoded: &[u8], - target_number: NumberFor, - validator_set: &ValidatorSet, -) -> Result, (ConsensusError, u32)> { - let proof = >::decode_all(&mut &*encoded) - .map_err(|_| (ConsensusError::InvalidJustification, 0))?; - 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. -#[cfg(not(feature = "bls-experimental"))] -pub(crate) fn verify_with_validator_set( - target_number: NumberFor, - validator_set: &ValidatorSet, - proof: &BeefyVersionedFinalityProof, -) -> Result<(), (ConsensusError, u32)> { - let mut signatures_checked = 0u32; - match proof { - VersionedFinalityProof::V1(signed_commitment) => { - if signed_commitment.signatures.len() != validator_set.len() || - signed_commitment.commitment.validator_set_id != validator_set.id() || - signed_commitment.commitment.block_number != target_number - { - return Err((ConsensusError::InvalidJustification, 0)); - } - - // Arrangement of signatures in the commitment should be in the same order - // as validators for that set. - let message = signed_commitment.commitment.encode(); - let valid_signatures = validator_set - .validators() - .into_iter() - .zip(signed_commitment.signatures.iter()) - .filter(|(id, signature)| { - signature - .as_ref() - .map(|sig| { - signatures_checked += 1; - BeefyKeystore::verify(*id, sig, &message[..]) - }) - .unwrap_or(false) - }) - .count(); - if valid_signatures >= crate::round::threshold(validator_set.len()) { - Ok(()) - } else { - Err((ConsensusError::InvalidJustification, signatures_checked)) - } - }, - } -} - -/// Verify the Beefy finality proof against the validator set at the block it was generated. -#[cfg(feature = "bls-experimental")] -pub(crate) fn verify_with_validator_set( - target_number: NumberFor, - validator_set: &ValidatorSet, - proof: &BeefyVersionedFinalityProof, -) -> Result<(), (ConsensusError, u32)> { - let mut signatures_checked = 0u32; - match proof { - VersionedFinalityProof::V1(signed_commitment) => { - if signed_commitment.signatures.len() != validator_set.len() || - signed_commitment.commitment.validator_set_id != validator_set.id() || - signed_commitment.commitment.block_number != target_number - { - return Err((ConsensusError::InvalidJustification, 0)); - } - - // Arrangement of signatures in the commitment should be in the same order - // as validators for that set. - let message = signed_commitment.commitment.encode(); - let valid_signatures = validator_set - .commitments() - .into_iter() - .zip(signed_commitment.signatures.iter()) - .filter(|(id, signature)| { - signature - .as_ref() - .map(|sig| { - signatures_checked += 1; - BeefyKeystore::verify(*id, sig, &message[..]) - }) - .unwrap_or(false) - }) - .count(); - if valid_signatures >= crate::round::threshold(validator_set.len()) { - Ok(()) - } else { - Err((ConsensusError::InvalidJustification, signatures_checked)) - } - }, - } -} - -#[cfg(test)] -pub(crate) mod tests { - use sp_consensus_beefy_etf::{ - known_payloads, test_utils::Keyring, Commitment, Payload, SignedCommitment, - VersionedFinalityProof, - }; - use substrate_test_runtime_client::runtime::Block; - - use super::*; - use crate::tests::make_beefy_ids; - - pub(crate) fn new_finality_proof( - block_num: NumberFor, - validator_set: &ValidatorSet, - keys: &[Keyring], - ) -> BeefyVersionedFinalityProof { - 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(); - VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }) - } - - #[test] - fn should_verify_with_validator_set() { - let keys = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let validator_set = - ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - - // build valid justification - let block_num = 42; - 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(); - - // wrong block number -> should fail verification - let good_proof = proof.clone().into(); - match verify_with_validator_set::(block_num + 1, &validator_set, &good_proof) { - Err((ConsensusError::InvalidJustification, 0)) => (), - e => assert!(false, "Got unexpected {:?}", e), - }; - - // wrong validator set id -> should fail verification - let good_proof = proof.clone().into(); - let other = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 1).unwrap(); - match verify_with_validator_set::(block_num, &other, &good_proof) { - Err((ConsensusError::InvalidJustification, 0)) => (), - e => assert!(false, "Got unexpected {:?}", e), - }; - - // wrong signatures length -> should fail verification - let mut bad_proof = proof.clone(); - // change length of signatures - let bad_signed_commitment = match bad_proof { - 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()) { - Err((ConsensusError::InvalidJustification, 0)) => (), - e => assert!(false, "Got unexpected {:?}", e), - }; - - // not enough signatures -> should fail verification - let mut bad_proof = proof.clone(); - let bad_signed_commitment = match bad_proof { - VersionedFinalityProof::V1(ref mut sc) => sc, - }; - // remove a signature (but same length) - *bad_signed_commitment.signatures.first_mut().unwrap() = None; - match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { - Err((ConsensusError::InvalidJustification, 2)) => (), - e => assert!(false, "Got unexpected {:?}", e), - }; - - // not enough _correct_ signatures -> should fail verification - let mut bad_proof = proof.clone(); - let bad_signed_commitment = match bad_proof { - VersionedFinalityProof::V1(ref mut sc) => sc, - }; - // 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, &validator_set, &bad_proof.into()) { - Err((ConsensusError::InvalidJustification, 3)) => (), - e => assert!(false, "Got unexpected {:?}", e), - }; - } - - #[test] - fn should_decode_and_verify_finality_proof() { - let keys = &[Keyring::Alice, Keyring::Bob]; - let validator_set = - ValidatorSet::new(make_beefy_ids(keys), 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 encoded = versioned_proof.encode(); - - // should successfully decode and verify - let verified = - decode_and_verify_finality_proof::(&encoded, block_num, &validator_set).unwrap(); - assert_eq!(verified, versioned_proof); - } -} diff --git a/client/consensus/beefy-etf/src/keystore.rs b/client/consensus/beefy-etf/src/keystore.rs deleted file mode 100644 index 16e9b9d..0000000 --- a/client/consensus/beefy-etf/src/keystore.rs +++ /dev/null @@ -1,642 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; -use sp_consensus_beefy_etf::{ - bls_crypto::AuthorityId as BeefyId, AuthorityIdBound, BeefyAuthorityId, BeefySignatureHasher, -}; -use sp_core::ecdsa; -#[cfg(feature = "bls-experimental")] -use sp_core::{bls377, ecdsa_bls377}; -use sp_crypto_hashing::keccak_256; -use sp_keystore::KeystorePtr; - -use codec::Decode; -use log::warn; -use std::marker::PhantomData; - -use crate::{error, LOG_TARGET}; - -/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a -/// wrapper around [`sp_keystore::Keystore`] and allows to customize -/// common cryptographic functionality. -pub(crate) struct BeefyKeystore( - Option, - PhantomData AuthorityId>, -); - -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: &[AuthorityId]) -> 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| { - store - .has_keys(&[(::to_raw_vec(k), BEEFY_KEY_TYPE)]) - }) - .cloned() - .collect(); - - if public.len() > 1 { - warn!( - target: LOG_TARGET, - "🥩 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. - // TODO: Remove this lint once the method is used. Or remove the function if it's not needed. - // https://github.com/ideal-lab5/idn-sdk/issues/63 - #[allow(dead_code)] - pub fn sign( - &self, - public: &AuthorityId, - message: &[u8], - ) -> Result<::Signature, error::Error> { - let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - - // ECDSA should use ecdsa_sign_prehashed since it needs to be hashed by keccak_256 instead - // of blake2. As such we need to deal with producing the signatures case-by-case - let signature_byte_array: Vec = match ::CRYPTO_ID { - ecdsa::CRYPTO_ID => { - let msg_hash = keccak_256(message); - let public: ecdsa::Public = ecdsa::Public::try_from(public.as_slice()).unwrap(); - - let sig = store - .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, &public, &msg_hash) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| { - error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()) - })?; - let sig_ref: &[u8] = sig.as_ref(); - sig_ref.to_vec() - }, - - #[cfg(feature = "bls-experimental")] - bls377::CRYPTO_ID => { - let public: bls377::Public = bls377::Public::try_from(public.as_slice()).unwrap(); - let sig = store - .bls377_sign(BEEFY_KEY_TYPE, &public, &message) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; - let sig_ref: &[u8] = sig.as_ref(); - sig_ref.to_vec() - }, - - #[cfg(all(feature = "bls-experimental"))] - ecdsa_bls377::CRYPTO_ID => { - let public: ecdsa_bls377::Public = - ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); - let sig = store - .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) - .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; - let sig_ref: &[u8] = sig.as_ref(); - sig_ref.to_vec() - }, - - _ => Err(error::Error::Keystore("key type is not supported by BEEFY Keystore".into()))?, - }; - - //check that `sig` has the expected result type - let signature = ::Signature::decode( - &mut signature_byte_array.as_slice(), - ) - .map_err(|_| { - error::Error::Signature(format!( - "invalid signature {:?} for key {:?}", - signature_byte_array, public - )) - })?; - - Ok(signature) - } - - /// Returns a vector of [`sp_consensus_beefy::crypto::Public`] keys which are currently - /// supported (i.e. found in the keystore). - pub fn public_keys(&self) -> Result, error::Error> { - let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - - let pk = match ::CRYPTO_ID { - ecdsa::CRYPTO_ID => store - .ecdsa_public_keys(BEEFY_KEY_TYPE) - .drain(..) - .map(|pk| AuthorityId::try_from(pk.as_ref())) - .collect::, _>>() - .or_else(|_| { - Err(error::Error::Keystore( - "unable to convert public key into authority id".into(), - )) - }), - - #[cfg(feature = "bls-experimental")] - bls377::CRYPTO_ID => store - .bls377_public_keys(BEEFY_KEY_TYPE) - .drain(..) - .map(|pk| AuthorityId::try_from(pk.as_ref())) - .collect::, _>>() - .or_else(|_| { - Err(error::Error::Keystore( - "unable to convert public key into authority id".into(), - )) - }), - - #[cfg(all(feature = "bls-experimental", feature = "full_crypto"))] - ecdsa_bls377::CRYPTO_ID => store - .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) - .drain(..) - .map(|pk| AuthorityId::try_from(pk.as_ref())) - .collect::, _>>() - .or_else(|_| { - Err(error::Error::Keystore( - "unable to convert public key into authority id".into(), - )) - }), - - _ => Err(error::Error::Keystore("key type is not supported by BEEFY Keystore".into())), - }; - - pk - } - - /// 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: &AuthorityId, - sig: &::Signature, - message: &[u8], - ) -> bool { - BeefyAuthorityId::::verify(public, sig, message) - } - - /// produces a BLS signature on the message - /// using ETF round keys derived ad-hoc (via ACSS.Recover) - #[cfg(feature = "bls-experimental")] - pub fn etf_sign( - &self, - public: &AuthorityId, - pok_bytes: &[u8], - message: &[u8], - threshold: u8, - ) -> Result<(BeefyId, ::Signature), error::Error> { - // debug!( - // target: LOG_TARGET, - // "🎲 [ETF][etf_sign] Public: {:?}, pok_bytes: {:?}, message: {:?}, threshold: {:?}", - // public, pok_bytes, message, threshold); - let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - - let public: bls377::Public = bls377::Public::try_from(public.as_slice()).unwrap(); - // debug!(target: LOG_TARGET, "🎲 [ETF][etf_sign] Public: {:?}", public); - let (etf_pubkey_bytes, sig) = store - .acss_recover(BEEFY_KEY_TYPE, &public, pok_bytes, message, threshold) - .map_err(|e| { - log::error!(target: LOG_TARGET, "🎲 [ETF][etf_sign] Error: {:?}", e); - error::Error::Signature(format!( - "Failed to recover a key from the provided proof of knowledge" - )) - })?; - - let mut signature_byte_array: &[u8] = sig.as_ref(); - let signature = - ::Signature::decode(&mut signature_byte_array) - .map_err(|_| { - error::Error::Signature(format!( - "invalid signature {:?} for key {:?}", - signature_byte_array, public - )) - })?; - let beef: BeefyId = BeefyId::from(etf_pubkey_bytes); - Ok((beef, signature)) - } -} - -impl From> for BeefyKeystore -where - ::Signature: Send + Sync, -{ - fn from(store: Option) -> BeefyKeystore { - BeefyKeystore(store, PhantomData) - } -} - -#[cfg(test)] -pub mod tests { - // #[cfg(feature = "bls-experimental")] - // use sp_consensus_beefy_etf::ecdsa_bls_crypto; - use sp_consensus_beefy_etf::{ - // ecdsa_crypto, - bls_crypto, - test_utils::{BeefySignerAuthority, Keyring}, - }; - use sp_core::Pair as PairT; - use sp_keystore::{testing::MemoryKeystore, Keystore}; - - use super::*; - use crate::error::Error; - - fn keystore() -> KeystorePtr { - MemoryKeystore::new().into() - } - - fn pair_verify_should_work< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let msg = b"I am Alice!"; - let sig = Keyring::::Alice.sign(b"I am Alice!"); - - assert!(>::verify( - &Keyring::Alice.public(), - &sig, - &msg.as_slice(), - )); - - // different public key -> fail - assert!(!>::verify( - &Keyring::Bob.public(), - &sig, - &msg.as_slice(), - )); - - let msg = b"I am not Alice!"; - - // different msg -> fail - assert!(!>::verify( - &Keyring::Alice.public(), - &sig, - &msg.as_slice(), - )); - } - - /// Generate key pair in the given store using the provided seed - fn generate_in_store( - store: KeystorePtr, - key_type: sp_application_crypto::KeyTypeId, - owner: Option>, - ) -> AuthorityId - where - AuthorityId: - AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - ::Pair: BeefySignerAuthority, - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - { - let optional_seed: Option = owner.map(|owner| owner.to_seed()); - - match ::CRYPTO_ID { - ecdsa::CRYPTO_ID => { - let pk = store.ecdsa_generate_new(key_type, optional_seed.as_deref()).ok().unwrap(); - AuthorityId::decode(&mut pk.as_ref()).unwrap() - }, - #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { - let pk = store - .ecdsa_bls377_generate_new(key_type, optional_seed.as_deref()) - .ok() - .unwrap(); - AuthorityId::decode(&mut pk.as_ref()).unwrap() - }, - #[cfg(feature = "bls-experimental")] - bls377::CRYPTO_ID => { - let pk = - store.bls377_generate_new(key_type, optional_seed.as_deref()).ok().unwrap(); - AuthorityId::decode(&mut pk.as_ref()).unwrap() - }, - _ => panic!("Requested CRYPTO_ID is not supported by the BEEFY Keyring"), - } - } - - // #[test] - // fn pair_verify_should_work_ecdsa() { - // pair_verify_should_work::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn pair_verify_should_work_ecdsa_n_bls() { - // pair_verify_should_work::(); - // } - - fn pair_works< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let want = ::Pair::from_string("//Alice", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Alice.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Bob", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Bob.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Charlie", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Charlie.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Dave", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Dave.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Eve", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Eve.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Ferdie", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Ferdie.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//One", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::One.pair().to_raw_vec(); - assert_eq!(want, got); - - let want = ::Pair::from_string("//Two", None) - .expect("Pair failed") - .to_raw_vec(); - let got = Keyring::::Two.pair().to_raw_vec(); - assert_eq!(want, got); - } - - // #[test] - // fn ecdsa_pair_works() { - // pair_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn ecdsa_n_bls_pair_works() { - // pair_works::(); - // } - - fn authority_id_works< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let store = keystore(); - - generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); - - let alice = Keyring::::Alice.public(); - - let bob = Keyring::Bob.public(); - let charlie = Keyring::Charlie.public(); - - let beefy_store: BeefyKeystore = Some(store).into(); - - let mut keys = vec![bob, charlie]; - - let id = beefy_store.authority_id(keys.as_slice()); - assert!(id.is_none()); - - keys.push(alice.clone()); - - let id = beefy_store.authority_id(keys.as_slice()).unwrap(); - assert_eq!(id, alice); - } - - // #[test] - // fn authority_id_works_for_ecdsa() { - // authority_id_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn authority_id_works_for_ecdsa_n_bls() { - // authority_id_works::(); - // } - - fn sign_works< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let store = keystore(); - - generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); - - let alice = Keyring::Alice.public(); - - let store: BeefyKeystore = Some(store).into(); - - let msg = b"are you involved or committed?"; - - let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = Keyring::::Alice.sign(msg); - - assert_eq!(sig1, sig2); - } - - // #[test] - // fn sign_works_for_ecdsa() { - // sign_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn sign_works_for_ecdsa_n_bls() { - // sign_works::(); - // } - - fn sign_error< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >( - expected_error_message: &str, - ) where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let store = keystore(); - - generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Bob)); - - let store: BeefyKeystore = Some(store).into(); - - let alice = Keyring::Alice.public(); - - let msg = b"are you involved or committed?"; - let sig = store.sign(&alice, msg).err().unwrap(); - 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"); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn sign_error_for_ecdsa_n_bls() { - // sign_error::("bls377_sign() failed"); - // } - - #[test] - fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); - - let alice = Keyring::Alice.public(); - let msg = b"are you involved or committed"; - - let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Keystore("no Keystore".to_string()); - assert_eq!(sig, err); - } - - fn verify_works< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - let store = keystore(); - - generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Alice)); - - let store: BeefyKeystore = Some(store).into(); - - let alice = Keyring::Alice.public(); - - // `msg` and `sig` match - let msg = b"are you involved or committed?"; - let sig = store.sign(&alice, msg).unwrap(); - assert!(BeefyKeystore::verify(&alice, &sig, msg)); - - // `msg and `sig` don't match - let msg = b"you are just involved"; - assert!(!BeefyKeystore::verify(&alice, &sig, msg)); - } - - // #[test] - // fn verify_works_for_ecdsa() { - // verify_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - - // fn verify_works_for_ecdsa_n_bls() { - // verify_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - #[test] - fn verify_works_for_bls() { - verify_works::(); - } - - // Note that we use keys with and without a seed for this test. - fn public_keys_works< - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - >() - where - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, - ::Pair: BeefySignerAuthority, - { - const TEST_TYPE: sp_application_crypto::KeyTypeId = - sp_application_crypto::KeyTypeId(*b"test"); - - let store = keystore(); - - // test keys - let _ = generate_in_store::(store.clone(), TEST_TYPE, Some(Keyring::Alice)); - let _ = generate_in_store::(store.clone(), TEST_TYPE, Some(Keyring::Bob)); - - // BEEFY keys - let _ = - generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Dave)); - let _ = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, Some(Keyring::Eve)); - - let _ = generate_in_store::(store.clone(), TEST_TYPE, None); - let _ = generate_in_store::(store.clone(), TEST_TYPE, None); - - let key1 = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, None); - let key2 = generate_in_store::(store.clone(), BEEFY_KEY_TYPE, None); - - let store: BeefyKeystore = Some(store).into(); - - let keys = store.public_keys().ok().unwrap(); - - assert!(keys.len() == 4); - assert!(keys.contains(&Keyring::Dave.public())); - assert!(keys.contains(&Keyring::Eve.public())); - assert!(keys.contains(&key1)); - assert!(keys.contains(&key2)); - } - - // #[test] - // fn public_keys_works_for_ecdsa_keystore() { - // public_keys_works::(); - // } - - // #[cfg(feature = "bls-experimental")] - // #[test] - // fn public_keys_works_for_ecdsa_n_bls() { - // public_keys_works::(); - // } -} diff --git a/client/consensus/beefy-etf/src/lib.rs b/client/consensus/beefy-etf/src/lib.rs deleted file mode 100644 index 890c615..0000000 --- a/client/consensus/beefy-etf/src/lib.rs +++ /dev/null @@ -1,760 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - communication::{ - notification::{ - BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, - BeefyVersionedFinalityProofStream, - }, - peers::KnownPeers, - request_response::{ - outgoing_requests_engine::OnDemandJustificationsEngine, BeefyJustifsRequestHandler, - }, - }, - error::Error, - import::BeefyBlockImport, - metrics::register_metrics, -}; -use futures::{stream::Fuse, FutureExt, StreamExt}; -use log::{debug, error, info, warn}; -use parking_lot::Mutex; -use prometheus::Registry; -use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; -use sc_consensus::BlockImport; -use sc_network::{NetworkRequest, NotificationService, ProtocolName}; -use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; -use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; -use sp_consensus::{Error as ConsensusError, SyncOracle}; -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::AuthorityId; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::ecdsa_crypto::AuthorityId; - -use sp_consensus_beefy_etf::{ - BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, -}; -use sp_keystore::KeystorePtr; -use sp_mmr_primitives::MmrApi; -use sp_runtime::traits::{Block, Header as HeaderT, NumberFor, Zero}; -use std::{ - collections::{BTreeMap, VecDeque}, - marker::PhantomData, - sync::Arc, - time::Duration, -}; - -mod aux_schema; -mod error; -mod keystore; -mod metrics; -mod round; -mod worker; - -pub mod communication; -pub mod import; -pub mod justification; - -use crate::{ - communication::{gossip::GossipValidator, peers::PeerReport}, - justification::BeefyVersionedFinalityProof, - keystore::BeefyKeystore, - metrics::VoterMetrics, - round::Rounds, - worker::{BeefyWorker, PersistedState}, -}; -pub use communication::beefy_protocol_name::{ - gossip_protocol_name, justifications_protocol_name as justifs_protocol_name, -}; -use sc_utils::mpsc::TracingUnboundedReceiver; -use sp_runtime::generic::OpaqueDigestItemId; - -#[cfg(test)] -mod tests; - -const LOG_TARGET: &str = "beefy"; - -const HEADER_SYNC_DELAY: Duration = Duration::from_secs(60); - -/// A convenience BEEFY client trait that defines all the type bounds a BEEFY client -/// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as -/// of today, Rust does not allow a type alias to be used as a trait bound. Tracking -/// issue is . -pub trait Client: - BlockchainEvents + HeaderBackend + Finalizer + Send + Sync -where - B: Block, - BE: Backend, -{ - // empty -} - -impl Client for T -where - B: Block, - BE: Backend, - T: BlockchainEvents - + HeaderBackend - + Finalizer - + ProvideRuntimeApi - + Send - + Sync, -{ - // empty -} - -/// Links between the block importer, the background voter and the RPC layer, -/// to be used by the voter. -#[derive(Clone)] -pub struct BeefyVoterLinks { - // BlockImport -> Voter links - /// Stream of BEEFY signed commitments from block import to voter. - pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, - - // Voter -> RPC links - /// Sends BEEFY signed commitments from voter to RPC. - 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 { - /// Stream of signed commitments coming from the voter. - 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( - wrapped_block_import: I, - backend: Arc, - runtime: Arc, - prometheus_registry: Option, -) -> (BeefyBlockImport, BeefyVoterLinks, BeefyRPCLinks) -where - B: Block, - BE: Backend, - I: BlockImport + Send + Sync, - RuntimeApi: ProvideRuntimeApi + Send + Sync, - RuntimeApi::Api: BeefyApi, -{ - // Voter -> RPC links - let (to_rpc_justif_sender, from_voter_justif_stream) = - 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(); - let metrics = register_metrics(prometheus_registry); - - // BlockImport - let import = BeefyBlockImport::new( - backend, - runtime, - wrapped_block_import, - to_voter_justif_sender, - metrics, - ); - let voter_links = BeefyVoterLinks { - from_block_import_justif_stream, - to_rpc_justif_sender, - to_rpc_best_block_sender, - }; - let rpc_links = BeefyRPCLinks { from_voter_best_beefy_stream, from_voter_justif_stream }; - - (import, voter_links, rpc_links) -} - -/// BEEFY gadget network parameters. -pub struct BeefyNetworkParams { - /// Network implementing gossip, requests and sync-oracle. - pub network: Arc, - /// Syncing service implementing a sync oracle and an event stream for peers. - pub sync: Arc, - /// Handle for receiving notification events. - pub notification_service: Box, - /// Chain specific BEEFY gossip protocol name. See - /// [`communication::beefy_protocol_name::gossip_protocol_name`]. - pub gossip_protocol_name: ProtocolName, - /// Chain specific BEEFY on-demand justifications protocol name. See - /// [`communication::beefy_protocol_name::justifications_protocol_name`]. - pub justifications_protocol_name: ProtocolName, - - pub _phantom: PhantomData, -} - -/// BEEFY gadget initialization parameters. -pub struct BeefyParams { - /// BEEFY client - pub client: Arc, - /// Client Backend - pub backend: Arc, - /// BEEFY Payload provider - pub payload_provider: P, - /// Runtime Api Provider - pub runtime: Arc, - /// Local key store - pub key_store: Option, - /// BEEFY voter network params - 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, - /// Handler for incoming BEEFY justifications requests from a remote peer. - pub on_demand_justifications_handler: BeefyJustifsRequestHandler, - /// Will be used when sending equivocation reports. - pub offchain_tx_pool_factory: OffchainTransactionPoolFactory, -} -/// Helper object holding BEEFY worker communication/gossip components. -/// -/// These are created once, but will be reused if worker is restarted/reinitialized. -pub(crate) struct BeefyComms { - pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, - pub gossip_report_stream: TracingUnboundedReceiver, - pub on_demand_justifications: OnDemandJustificationsEngine, -} - -/// Helper builder object for building [worker::BeefyWorker]. -/// -/// It has to do it in two steps: initialization and build, because the first step can sleep waiting -/// for certain chain and backend conditions, and while sleeping we still need to pump the -/// GossipEngine. Once initialization is done, the GossipEngine (and other pieces) are added to get -/// the complete [worker::BeefyWorker] object. -pub(crate) struct BeefyWorkerBuilder { - // utilities - backend: Arc, - runtime: Arc, - key_store: BeefyKeystore, - // voter metrics - metrics: Option, - persisted_state: PersistedState, -} - -impl BeefyWorkerBuilder -where - B: Block + codec::Codec, - BE: Backend, - R: ProvideRuntimeApi, - R::Api: BeefyApi, -{ - /// This will wait for the chain to enable BEEFY (if not yet enabled) and also wait for the - /// backend to sync all headers required by the voter to build a contiguous chain of mandatory - /// justifications. Then it builds the initial voter state using a combination of previously - /// persisted state in AUX DB and latest chain information/progress. - /// - /// Returns a sane `BeefyWorkerBuilder` that can build the `BeefyWorker`. - pub async fn async_initialize( - backend: Arc, - runtime: Arc, - key_store: BeefyKeystore, - metrics: Option, - min_block_delta: u32, - gossip_validator: Arc>, - finality_notifications: &mut Fuse>, - ) -> Result { - // Wait for BEEFY pallet to be active before starting voter. - let (beefy_genesis, best_grandpa) = - wait_for_runtime_pallet(&*runtime, finality_notifications).await?; - - let persisted_state = Self::load_or_init_state( - beefy_genesis, - best_grandpa, - min_block_delta, - backend.clone(), - runtime.clone(), - &key_store, - &metrics, - ) - .await?; - // Update the gossip validator with the right starting round and set id. - persisted_state - .gossip_filter_config() - .map(|f| gossip_validator.update_filter(f))?; - - Ok(BeefyWorkerBuilder { backend, runtime, key_store, metrics, persisted_state }) - } - - /// Takes rest of missing pieces as params and builds the `BeefyWorker`. - pub fn build( - self, - payload_provider: P, - sync: Arc, - comms: BeefyComms, - links: BeefyVoterLinks, - pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, - offchain_tx_pool_factory: OffchainTransactionPoolFactory, - ) -> BeefyWorker { - BeefyWorker { - backend: self.backend, - runtime: self.runtime, - key_store: self.key_store, - metrics: self.metrics, - persisted_state: self.persisted_state, - payload_provider, - sync, - comms, - links, - pending_justifications, - offchain_tx_pool_factory, - } - } - - // If no persisted state present, walk back the chain from first GRANDPA notification to either: - // - 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. - async fn init_state( - beefy_genesis: NumberFor, - best_grandpa: ::Header, - min_block_delta: u32, - backend: Arc, - runtime: Arc, - ) -> Result, Error> { - let blockchain = backend.blockchain(); - - let beefy_genesis = runtime - .runtime_api() - .beefy_genesis(best_grandpa.hash()) - .ok() - .flatten() - .filter(|genesis| *genesis == beefy_genesis) - .ok_or_else(|| Error::Backend("BEEFY pallet expected to be active.".into()))?; - // 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. - let mut sessions = VecDeque::new(); - let mut header = best_grandpa.clone(); - let state = loop { - if let Some(true) = blockchain - .justifications(header.hash()) - .ok() - .flatten() - .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) - { - debug!( - target: LOG_TARGET, - "🥩 Initialize BEEFY voter at last BEEFY finalized block: {:?}.", - *header.number() - ); - let best_beefy = *header.number(); - // If no session boundaries detected so far, just initialize new rounds here. - if sessions.is_empty() { - let active_set = - expect_validator_set(runtime.as_ref(), backend.as_ref(), &header).await?; - let mut rounds = Rounds::new(best_beefy, active_set); - // Mark the round as already finalized. - rounds.conclude(best_beefy); - sessions.push_front(rounds); - } - let state = PersistedState::checked_new( - best_grandpa, - best_beefy, - sessions, - min_block_delta, - beefy_genesis, - ) - .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; - break state; - } - - if *header.number() == beefy_genesis { - // We've reached BEEFY genesis, initialize voter here. - let genesis_set = - expect_validator_set(runtime.as_ref(), backend.as_ref(), &header).await?; - info!( - target: LOG_TARGET, - "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ - Starting voting rounds at block {:?}, genesis validator set {:?}.", - beefy_genesis, - genesis_set, - ); - - sessions.push_front(Rounds::new(beefy_genesis, genesis_set)); - break PersistedState::checked_new( - best_grandpa, - Zero::zero(), - sessions, - min_block_delta, - beefy_genesis, - ) - .ok_or_else(|| Error::Backend("Invalid BEEFY chain".into()))?; - } - - if let Some(active) = find_authorities_change::(&header) { - debug!( - target: LOG_TARGET, - "🥩 Marking block {:?} as BEEFY Mandatory.", - *header.number() - ); - sessions.push_front(Rounds::new(*header.number(), active)); - } - - // Move up the chain. - header = wait_for_parent_header(blockchain, header, HEADER_SYNC_DELAY).await?; - }; - - aux_schema::write_current_version(backend.as_ref())?; - aux_schema::write_voter_state(backend.as_ref(), &state)?; - Ok(state) - } - - async fn load_or_init_state( - beefy_genesis: NumberFor, - best_grandpa: ::Header, - min_block_delta: u32, - backend: Arc, - runtime: Arc, - key_store: &BeefyKeystore, - metrics: &Option, - ) -> Result, Error> { - // Initialize voter state from AUX DB if compatible. - if let Some(mut state) = crate::aux_schema::load_persistent(backend.as_ref())? - // Verify state pallet genesis matches runtime. - .filter(|state| state.pallet_genesis() == beefy_genesis) - { - // Overwrite persisted state with current best GRANDPA block. - state.set_best_grandpa(best_grandpa.clone()); - // Overwrite persisted data with newly provided `min_block_delta`. - state.set_min_block_delta(min_block_delta); - debug!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db: {:?}.", state); - - // Make sure that all the headers that we need have been synced. - let mut new_sessions = vec![]; - let mut header = best_grandpa.clone(); - while *header.number() > state.best_beefy() { - if state.voting_oracle().can_add_session(*header.number()) { - if let Some(active) = find_authorities_change::(&header) { - new_sessions.push((active, *header.number())); - } - } - header = - wait_for_parent_header(backend.blockchain(), header, HEADER_SYNC_DELAY).await?; - } - - // Make sure we didn't miss any sessions during node restart. - for (validator_set, new_session_start) in new_sessions.drain(..).rev() { - debug!( - target: LOG_TARGET, - "🥩 Handling missed BEEFY session after node restart: {:?}.", - new_session_start - ); - state.init_session_at(new_session_start, validator_set, key_store, metrics); - } - return Ok(state); - } - - // No valid voter-state persisted, re-initialize from pallet genesis. - Self::init_state(beefy_genesis, best_grandpa, min_block_delta, backend, runtime).await - } -} - -/// 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 - B: Block, - BE: Backend, - C: Client + BlockBackend, - P: PayloadProvider + Clone, - R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi>, - N: GossipNetwork + NetworkRequest + Send + Sync + 'static, - S: GossipSyncing + SyncOracle + 'static, -{ - let BeefyParams { - client, - backend, - payload_provider, - runtime, - key_store, - network_params, - min_block_delta, - prometheus_registry, - links, - mut on_demand_justifications_handler, - offchain_tx_pool_factory, - } = beefy_params; - - let BeefyNetworkParams { - network, - sync, - notification_service, - gossip_protocol_name, - justifications_protocol_name, - .. - } = network_params; - - let metrics = register_metrics(prometheus_registry.clone()); - - // Subscribe to finality notifications and justifications before waiting for runtime pallet and - // reuse the streams, so we don't miss notifications while waiting for pallet to be available. - let mut finality_notifications = client.finality_notification_stream().fuse(); - let mut block_import_justif = links.from_block_import_justif_stream.subscribe(100_000).fuse(); - - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - // Default votes filter is to discard everything. - // Validator is updated later with correct starting round and set id. - let (gossip_validator, gossip_report_stream) = - communication::gossip::GossipValidator::new(known_peers.clone()); - let gossip_validator = Arc::new(gossip_validator); - let gossip_engine = GossipEngine::new( - network.clone(), - sync.clone(), - notification_service, - gossip_protocol_name.clone(), - gossip_validator.clone(), - None, - ); - - // The `GossipValidator` adds and removes known peers based on valid votes and network - // events. - let on_demand_justifications = OnDemandJustificationsEngine::new( - network.clone(), - justifications_protocol_name.clone(), - known_peers, - prometheus_registry.clone(), - ); - let mut beefy_comms = BeefyComms { - gossip_engine, - gossip_validator, - gossip_report_stream, - on_demand_justifications, - }; - - if let Some(ref keystore) = key_store { - let mut runtime_api = runtime.runtime_api(); - runtime_api.register_extension(sp_keystore::KeystoreExt::from(keystore.clone())); - } - - // let offchain_tx_pool_factory = - // OffchainTransactionPoolFactory::new(transaction_pool.clone()); - // runtime.runtime_api().register_extension(offchain_tx_pool_factory - // .offchain_transaction_pool(::Hash::default())); //TODO - - // We re-create and re-run the worker in this loop in order to quickly reinit and resume after - // select recoverable errors. - loop { - // Make sure to pump gossip engine while waiting for initialization conditions. - let worker_builder = loop { - futures::select! { - builder_init_result = BeefyWorkerBuilder::async_initialize( - backend.clone(), - runtime.clone(), - key_store.clone().into(), - metrics.clone(), - min_block_delta, - beefy_comms.gossip_validator.clone(), - &mut finality_notifications, - ).fuse() => { - match builder_init_result { - Ok(builder) => break builder, - Err(e) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", e); - return - }, - } - }, - // Pump peer reports - _ = &mut beefy_comms.gossip_report_stream.next() => { - continue - }, - // Pump gossip engine. - _ = &mut beefy_comms.gossip_engine => { - error!(target: LOG_TARGET, "🥩 Gossip engine has unexpectedly terminated."); - return - } - } - }; - - let worker = worker_builder.build( - payload_provider.clone(), - sync.clone(), - beefy_comms, - links.clone(), - BTreeMap::new(), - offchain_tx_pool_factory.clone(), - ); - - match futures::future::select( - Box::pin(worker.run(&mut block_import_justif, &mut finality_notifications)), - Box::pin(on_demand_justifications_handler.run()), - ) - .await - { - // On `ConsensusReset` error, just reinit and restart voter. - futures::future::Either::Left(((error::Error::ConsensusReset, reuse_comms), _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Restarting voter.", error::Error::ConsensusReset); - beefy_comms = reuse_comms; - continue; - }, - // On other errors, bring down / finish the task. - futures::future::Either::Left(((worker_err, _), _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", worker_err) - }, - futures::future::Either::Right((odj_handler_err, _)) => { - error!(target: LOG_TARGET, "🥩 Error: {:?}. Terminating.", odj_handler_err) - }, - }; - return; - } -} - -/// Waits until the parent header of `current` is available and returns it. -/// -/// When the node uses GRANDPA warp sync it initially downloads only the mandatory GRANDPA headers. -/// The rest of the headers (gap sync) are lazily downloaded later. But the BEEFY voter also needs -/// the headers in range `[beefy_genesis..=best_grandpa]` to be available. This helper method -/// enables us to wait until these headers have been synced. -async fn wait_for_parent_header( - blockchain: &BC, - current: ::Header, - delay: Duration, -) -> Result<::Header, Error> -where - B: Block, - BC: BlockchainBackend, -{ - if *current.number() == Zero::zero() { - let msg = format!("header {} is Genesis, there is no parent for it", current.hash()); - warn!(target: LOG_TARGET, "{}", msg); - return Err(Error::Backend(msg)); - } - loop { - match blockchain - .header(*current.parent_hash()) - .map_err(|e| Error::Backend(e.to_string()))? - { - Some(parent) => return Ok(parent), - None => { - info!( - target: LOG_TARGET, - "🥩 Parent of header number {} not found. \ - BEEFY gadget waiting for header sync to finish ...", - current.number() - ); - tokio::time::sleep(delay).await; - }, - } - } -} - -/// 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( - runtime: &R, - finality: &mut Fuse>, -) -> Result<(NumberFor, ::Header), Error> -where - B: Block, - R: ProvideRuntimeApi, - R::Api: BeefyApi, -{ - info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); - loop { - let notif = finality.next().await.ok_or_else(|| { - let err_msg = "🥩 Finality stream has unexpectedly terminated.".into(); - error!(target: LOG_TARGET, "{}", err_msg); - Error::Backend(err_msg) - })?; - let at = notif.header.hash(); - if let Some(start) = runtime.runtime_api().beefy_genesis(at).ok().flatten() { - if *notif.header.number() >= start { - // Beefy pallet available, return header for best grandpa at the time. - info!( - target: LOG_TARGET, - "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", - notif.header.number(), start - ); - return Ok((start, notif.header)); - } - } - } -} - -/// Provides validator set active `at_header`. It tries to get it from state, otherwise falls -/// back to walk up the chain looking the validator set enactment in header digests. -/// -/// Note: function will `async::sleep()` when walking back the chain if some needed header hasn't -/// been synced yet (as it happens when warp syncing when headers are synced in the background). -async fn expect_validator_set( - runtime: &R, - backend: &BE, - at_header: &B::Header, -) -> Result, Error> -where - B: Block, - BE: Backend, - R: ProvideRuntimeApi, - R::Api: BeefyApi, -{ - let blockchain = backend.blockchain(); - // Walk up the chain looking for the validator set active at 'at_header'. Process both state and - // header digests. - debug!( - target: LOG_TARGET, - "🥩 Trying to find validator set active at header(number {:?}, hash {:?})", - at_header.number(), - at_header.hash() - ); - let mut header = at_header.clone(); - loop { - debug!(target: LOG_TARGET, "🥩 Looking for auth set change at block number: {:?}", *header.number()); - if let Ok(Some(active)) = runtime.runtime_api().validator_set(header.hash()) { - return Ok(active); - } else { - match find_authorities_change::(&header) { - Some(active) => return Ok(active), - // Move up the chain. Ultimately we'll get it from chain genesis state, or error out - // there. - None => - header = wait_for_parent_header(blockchain, header, HEADER_SYNC_DELAY) - .await - .map_err(|e| Error::Backend(e.to_string()))?, - } - } - } -} - -/// 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> -where - B: Block, -{ - let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - - let filter = |log: ConsensusLog| match log { - ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), - _ => None, - }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) -} diff --git a/client/consensus/beefy-etf/src/metrics.rs b/client/consensus/beefy-etf/src/metrics.rs deleted file mode 100644 index ef3928d..0000000 --- a/client/consensus/beefy-etf/src/metrics.rs +++ /dev/null @@ -1,345 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! BEEFY Prometheus metrics definition - -use crate::LOG_TARGET; -use log::{debug, error}; -use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; - -/// Helper trait for registering BEEFY metrics to Prometheus registry. -pub(crate) trait PrometheusRegister: Sized { - const DESCRIPTION: &'static str; - fn register(registry: &Registry) -> Result; -} - -/// BEEFY voting-related metrics exposed through Prometheus -#[derive(Clone, Debug)] -pub struct VoterMetrics { - /// Current active validator set id - pub beefy_validator_set_id: Gauge, - /// Total number of votes sent by this node - pub beefy_votes_sent: Counter, - /// Best block finalized by BEEFY - pub beefy_best_block: Gauge, - /// Best block BEEFY voted on - pub beefy_best_voted: Gauge, - /// Next block BEEFY should vote on - pub beefy_should_vote_on: Gauge, - /// Number of sessions with lagging signed commitment on mandatory block - pub beefy_lagging_sessions: Counter, - /// Number of times no Authority public key found in store - pub beefy_no_authority_found_in_store: Counter, - /// Number of good votes successfully handled - pub beefy_good_votes_processed: Counter, - /// Number of equivocation votes received - pub beefy_equivocation_votes: Counter, - /// Number of invalid votes received - pub beefy_invalid_votes: Counter, - /// Number of valid but stale votes received - pub beefy_stale_votes: Counter, - /// Number of currently buffered justifications - pub beefy_buffered_justifications: Gauge, - /// Number of valid but stale justifications received - pub beefy_stale_justifications: Counter, - /// Number of valid justifications successfully imported - pub beefy_imported_justifications: Counter, - /// Number of justifications dropped due to full buffers - pub beefy_buffered_justifications_dropped: Counter, -} - -impl PrometheusRegister for VoterMetrics { - const DESCRIPTION: &'static str = "voter"; - fn register(registry: &Registry) -> Result { - Ok(Self { - beefy_validator_set_id: register( - Gauge::new( - "substrate_beefy_validator_set_id", - "Current BEEFY active validator set id.", - )?, - registry, - )?, - beefy_votes_sent: register( - Counter::new("substrate_beefy_votes_sent", "Number of votes sent by this node")?, - registry, - )?, - beefy_best_block: register( - Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?, - registry, - )?, - beefy_best_voted: register( - Gauge::new("substrate_beefy_best_voted", "Best block voted on by BEEFY")?, - registry, - )?, - beefy_should_vote_on: register( - Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?, - registry, - )?, - beefy_lagging_sessions: register( - Counter::new( - "substrate_beefy_lagging_sessions", - "Number of sessions with lagging signed commitment on mandatory block", - )?, - registry, - )?, - beefy_no_authority_found_in_store: register( - Counter::new( - "substrate_beefy_no_authority_found_in_store", - "Number of times no Authority public key found in store", - )?, - registry, - )?, - beefy_good_votes_processed: register( - Counter::new( - "substrate_beefy_successful_handled_votes", - "Number of good votes successfully handled", - )?, - registry, - )?, - beefy_equivocation_votes: register( - Counter::new( - "substrate_beefy_equivocation_votes", - "Number of equivocation votes received", - )?, - registry, - )?, - beefy_invalid_votes: register( - Counter::new("substrate_beefy_invalid_votes", "Number of invalid votes received")?, - registry, - )?, - beefy_stale_votes: register( - Counter::new( - "substrate_beefy_stale_votes", - "Number of valid but stale votes received", - )?, - registry, - )?, - beefy_buffered_justifications: register( - Gauge::new( - "substrate_beefy_buffered_justifications", - "Number of currently buffered justifications", - )?, - registry, - )?, - beefy_stale_justifications: register( - Counter::new( - "substrate_beefy_stale_justifications", - "Number of valid but stale justifications received", - )?, - registry, - )?, - beefy_imported_justifications: register( - Counter::new( - "substrate_beefy_imported_justifications", - "Number of valid justifications successfully imported", - )?, - registry, - )?, - beefy_buffered_justifications_dropped: register( - Counter::new( - "substrate_beefy_buffered_justifications_dropped", - "Number of justifications dropped due to full buffers", - )?, - registry, - )?, - }) - } -} - -/// BEEFY block-import-related metrics exposed through Prometheus -#[derive(Clone, Debug)] -pub struct BlockImportMetrics { - /// Number of Good Justification imports - pub beefy_good_justification_imports: Counter, - /// Number of Bad Justification imports - pub beefy_bad_justification_imports: Counter, -} - -impl PrometheusRegister for BlockImportMetrics { - const DESCRIPTION: &'static str = "block-import"; - fn register(registry: &Registry) -> Result { - Ok(Self { - beefy_good_justification_imports: register( - Counter::new( - "substrate_beefy_good_justification_imports", - "Number of good justifications on block-import", - )?, - registry, - )?, - beefy_bad_justification_imports: register( - Counter::new( - "substrate_beefy_bad_justification_imports", - "Number of bad justifications on block-import", - )?, - registry, - )?, - }) - } -} - -/// BEEFY on-demand-justifications-related metrics exposed through Prometheus -#[derive(Clone, Debug)] -pub struct OnDemandIncomingRequestsMetrics { - /// Number of Successful Justification responses - pub beefy_successful_justification_responses: Counter, - /// Number of Failed Justification responses - pub beefy_failed_justification_responses: Counter, -} - -impl PrometheusRegister for OnDemandIncomingRequestsMetrics { - const DESCRIPTION: &'static str = "on-demand incoming justification requests"; - fn register(registry: &Registry) -> Result { - Ok(Self { - beefy_successful_justification_responses: register( - Counter::new( - "substrate_beefy_successful_justification_responses", - "Number of Successful Justification responses", - )?, - registry, - )?, - beefy_failed_justification_responses: register( - Counter::new( - "substrate_beefy_failed_justification_responses", - "Number of Failed Justification responses", - )?, - registry, - )?, - }) - } -} - -/// BEEFY on-demand-justifications-related metrics exposed through Prometheus -#[derive(Clone, Debug)] -pub struct OnDemandOutgoingRequestsMetrics { - /// Number of times there was no good peer to request justification from - pub beefy_on_demand_justification_no_peer_to_request_from: Counter, - /// Number of on-demand justification peer refused valid requests - pub beefy_on_demand_justification_peer_refused: Counter, - /// Number of on-demand justification peer error - pub beefy_on_demand_justification_peer_error: Counter, - /// Number of on-demand justification invalid proof - pub beefy_on_demand_justification_invalid_proof: Counter, - /// Number of on-demand justification good proof - pub beefy_on_demand_justification_good_proof: Counter, -} - -impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { - const DESCRIPTION: &'static str = "on-demand outgoing justification requests"; - fn register(registry: &Registry) -> Result { - Ok(Self { - beefy_on_demand_justification_no_peer_to_request_from: register( - Counter::new( - "substrate_beefy_on_demand_justification_no_peer_to_request_from", - "Number of times there was no good peer to request justification from", - )?, - registry, - )?, - beefy_on_demand_justification_peer_refused: register( - Counter::new( - "beefy_on_demand_justification_peer_refused", - "Number of on-demand justification peer refused valid requests", - )?, - registry, - )?, - beefy_on_demand_justification_peer_error: register( - Counter::new( - "substrate_beefy_on_demand_justification_peer_error", - "Number of on-demand justification peer error", - )?, - registry, - )?, - beefy_on_demand_justification_invalid_proof: register( - Counter::new( - "substrate_beefy_on_demand_justification_invalid_proof", - "Number of on-demand justification invalid proof", - )?, - registry, - )?, - beefy_on_demand_justification_good_proof: register( - Counter::new( - "substrate_beefy_on_demand_justification_good_proof", - "Number of on-demand justification good proof", - )?, - registry, - )?, - }) - } -} - -pub(crate) fn register_metrics( - prometheus_registry: Option, -) -> Option { - prometheus_registry.as_ref().map(T::register).and_then(|result| match result { - Ok(metrics) => { - debug!(target: LOG_TARGET, "🥩 Registered {} metrics", T::DESCRIPTION); - Some(metrics) - }, - Err(err) => { - error!( - target: LOG_TARGET, - "🥩 Failed to register {} metrics: {:?}", - T::DESCRIPTION, - err - ); - None - }, - }) -} - -// Note: we use the `format` macro to convert an expr into a `u64`. This will fail, -// if expr does not derive `Display`. -#[macro_export] -macro_rules! metric_set { - ($metrics:expr, $m:ident, $v:expr) => {{ - let val: u64 = format!("{}", $v).parse().unwrap(); - - if let Some(metrics) = $metrics.as_ref() { - metrics.$m.set(val); - } - }}; -} - -#[macro_export] -macro_rules! metric_inc { - ($metrics:expr, $m:ident) => {{ - if let Some(metrics) = $metrics.as_ref() { - metrics.$m.inc(); - } - }}; -} - -#[macro_export] -macro_rules! metric_get { - ($metrics:expr, $m:ident) => {{ - $metrics.as_ref().map(|metrics| metrics.$m.clone()) - }}; -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - - #[test] - fn should_register_metrics() { - let registry = Some(Registry::new()); - assert!(register_metrics::(registry.clone()).is_some()); - assert!(register_metrics::(registry.clone()).is_some()); - assert!(register_metrics::(registry.clone()).is_some()); - assert!(register_metrics::(registry.clone()).is_some()); - } -} diff --git a/client/consensus/beefy-etf/src/round.rs b/client/consensus/beefy-etf/src/round.rs deleted file mode 100644 index e35b671..0000000 --- a/client/consensus/beefy-etf/src/round.rs +++ /dev/null @@ -1,524 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::LOG_TARGET; - -use codec::{Decode, Encode}; -use log::{debug, info}; - -// #[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::{AuthorityId, Signature}; - -// #[cfg(not(feature = "bls-experimental"))] -// use sp_consensus_beefy_etf::ecdsa_crypto::{AuthorityId, Signature}; - -use sp_consensus_beefy_etf::{ - Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, -}; -use sp_runtime::traits::{Block, NumberFor}; -use std::collections::BTreeMap; - -/// 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)] -pub(crate) struct RoundTracker { - votes: BTreeMap, -} - -impl RoundTracker { - fn add_vote(&mut self, vote: (AuthorityId, Signature)) -> bool { - if self.votes.contains_key(&vote.0) { - return false; - } - - self.votes.insert(vote.0, vote.1); - true - } - - fn is_done(&self, threshold: usize) -> bool { - self.votes.len() >= threshold - } -} - -/// Minimum size of `authorities` subset that produced valid signatures for a block to finalize. -pub fn threshold(authorities: usize) -> usize { - let faulty = authorities.saturating_sub(1) / 3; - authorities - faulty -} - -#[derive(Debug, PartialEq)] -pub enum VoteImportResult { - Ok, - RoundConcluded(SignedCommitment, Signature>), - Equivocation(EquivocationProof, AuthorityId, Signature>), - Invalid, - Stale, -} - -/// Keeps track of all voting rounds (block numbers) within a session. -/// Only round numbers > `best_done` are of interest, all others are considered stale. -/// -/// 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>, RoundTracker>, - previous_votes: - BTreeMap<(AuthorityId, NumberFor), VoteMessage, AuthorityId, Signature>>, - session_start: NumberFor, - validator_set: ValidatorSet, - mandatory_done: bool, - best_done: Option>, -} - -impl Rounds -where - B: Block, -{ - pub(crate) fn new( - session_start: NumberFor, - validator_set: ValidatorSet, - ) -> Self { - Rounds { - rounds: BTreeMap::new(), - previous_votes: BTreeMap::new(), - session_start, - validator_set, - mandatory_done: false, - best_done: None, - } - } - - pub(crate) fn validator_set(&self) -> &ValidatorSet { - &self.validator_set - } - - pub(crate) fn validator_set_id(&self) -> ValidatorSetId { - self.validator_set.id() - } - - pub(crate) fn validators(&self) -> &[AuthorityId] { - self.validator_set.validators() - } - - pub(crate) fn session_start(&self) -> NumberFor { - self.session_start - } - - pub(crate) fn mandatory_done(&self) -> bool { - self.mandatory_done - } - - pub(crate) fn add_vote( - &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> VoteImportResult { - let num = vote.commitment.block_number; - let vote_key = (vote.id.clone(), num); - - if num < self.session_start || Some(num) <= self.best_done { - debug!(target: LOG_TARGET, "🥩 received vote for old stale round {:?}, ignoring", num); - return VoteImportResult::Stale; - } else if vote.commitment.validator_set_id != self.validator_set_id() { - debug!( - target: LOG_TARGET, - "🥩 expected set_id {:?}, ignoring vote {:?}.", - self.validator_set_id(), - vote, - ); - return VoteImportResult::Invalid; - } else if !self.validators().iter().any(|id| &vote.id == id) { - debug!( - target: LOG_TARGET, - "🥩 received vote {:?} from validator that is not in the validator set, ignoring", - vote - ); - return VoteImportResult::Invalid; - } - - if let Some(previous_vote) = self.previous_votes.get(&vote_key) { - // is the same public key voting for a different payload? - if previous_vote.commitment.payload != vote.commitment.payload { - debug!( - target: LOG_TARGET, - "🥩 detected equivocated vote: 1st: {:?}, 2nd: {:?}", previous_vote, vote - ); - return VoteImportResult::Equivocation(EquivocationProof { - first: previous_vote.clone(), - second: vote, - }); - } - } else { - // this is the first vote sent by `id` for `num`, all good - self.previous_votes.insert(vote_key, vote.clone()); - } - - // add valid vote - let round = self.rounds.entry(vote.commitment.clone()).or_default(); - if round.add_vote((vote.id, vote.signature)) && - round.is_done(threshold(self.validator_set.len())) - { - if let Some(round) = self.rounds.remove_entry(&vote.commitment) { - return VoteImportResult::RoundConcluded(self.signed_commitment(round)); - } - } - VoteImportResult::Ok - } - - fn signed_commitment( - &mut self, - round: (Commitment>, RoundTracker), - ) -> SignedCommitment, Signature> { - let votes = round.1.votes; - let signatures = self - .validators() - .iter() - .map(|authority_id| votes.get(authority_id).cloned()) - .collect(); - SignedCommitment { commitment: round.0, signatures } - } - - pub(crate) fn conclude(&mut self, round_num: NumberFor) { - // Remove this and older (now stale) rounds. - self.rounds.retain(|commitment, _| commitment.block_number > round_num); - self.previous_votes.retain(|&(_, number), _| number > round_num); - self.mandatory_done = self.mandatory_done || round_num == self.session_start; - self.best_done = self.best_done.max(Some(round_num)); - if round_num == self.session_start { - info!(target: LOG_TARGET, "🥩 Concluded mandatory round #{}", round_num); - } else { - debug!(target: LOG_TARGET, "🥩 Concluded optional round #{}", round_num); - } - } -} - -#[cfg(test)] -mod tests { - use sc_network_test::Block; - - use sp_consensus_beefy_etf::{ - known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, EquivocationProof, Payload, - SignedCommitment, ValidatorSet, VoteMessage, - }; - - use super::{threshold, AuthorityId, Block as BlockT, RoundTracker, Rounds}; - use crate::round::VoteImportResult; - - impl Rounds - where - B: BlockT, - { - pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { - self.mandatory_done = done; - } - } - - #[test] - fn round_tracker() { - let mut rt = RoundTracker::default(); - let bob_vote = (Keyring::Bob.public(), Keyring::::Bob.sign(b"I am committed")); - let threshold = 2; - - // adding new vote allowed - assert!(rt.add_vote(bob_vote.clone())); - // adding existing vote not allowed - assert!(!rt.add_vote(bob_vote)); - - // vote is not done - assert!(!rt.is_done(threshold)); - - let alice_vote = - (Keyring::Alice.public(), Keyring::::Alice.sign(b"I am committed")); - // adding new vote (self vote this time) allowed - assert!(rt.add_vote(alice_vote)); - - // vote is now done - assert!(rt.is_done(threshold)); - } - - #[test] - fn vote_threshold() { - assert_eq!(threshold(1), 1); - assert_eq!(threshold(2), 2); - assert_eq!(threshold(3), 3); - assert_eq!(threshold(4), 3); - assert_eq!(threshold(100), 67); - assert_eq!(threshold(300), 201); - } - - #[test] - fn new_rounds() { - sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - 42, - ) - .unwrap(); - - let session_start = 1u64.into(); - 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() - ], - rounds.validators() - ); - } - - #[test] - fn add_and_conclude_votes() { - sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - Keyring::Eve.public(), - ], - vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - Keyring::Eve.public(), - ], - Default::default(), - ) - .unwrap(); - let validator_set_id = validators.id(); - - let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); - let block_number = 1; - let commitment = Commitment { block_number, payload, validator_set_id }; - let mut vote = VoteMessage { - id: Keyring::Alice.public(), - commitment: commitment.clone(), - signature: Keyring::::Alice.sign(b"I am committed"), - }; - // add 1st good vote - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - - // double voting (same vote), ok, no effect - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - - vote.id = Keyring::Dave.public(); - vote.signature = Keyring::::Dave.sign(b"I am committed"); - // invalid vote (Dave is not a validator) - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Invalid); - - vote.id = Keyring::Bob.public(); - vote.signature = Keyring::::Bob.sign(b"I am committed"); - // add 2nd good vote - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); - - vote.id = Keyring::Charlie.public(); - vote.signature = Keyring::::Charlie.sign(b"I am committed"); - // add 3rd good vote -> round concluded -> signatures present - assert_eq!( - rounds.add_vote(vote.clone()), - VoteImportResult::RoundConcluded(SignedCommitment { - commitment, - signatures: vec![ - Some(Keyring::::Alice.sign(b"I am committed")), - Some(Keyring::::Bob.sign(b"I am committed")), - Some(Keyring::::Charlie.sign(b"I am committed")), - None, - ] - }) - ); - rounds.conclude(block_number); - - vote.id = Keyring::Eve.public(); - vote.signature = Keyring::::Eve.sign(b"I am committed"); - // Eve is a validator, but round was concluded, adding vote disallowed - assert_eq!(rounds.add_vote(vote), VoteImportResult::Stale); - } - - #[test] - fn old_rounds_not_accepted() { - sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - 42, - ) - .unwrap(); - let validator_set_id = validators.id(); - - // active rounds starts at block 10 - let session_start = 10u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - // vote on round 9 - let block_number = 9; - let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); - let commitment = Commitment { block_number, payload, validator_set_id }; - let mut vote = VoteMessage { - id: Keyring::Alice.public(), - commitment, - signature: Keyring::::Alice.sign(b"I am committed"), - }; - // add vote for previous session, should fail - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); - // no votes present - assert!(rounds.rounds.is_empty()); - - // simulate 11 was concluded - rounds.best_done = Some(11); - // add votes for current session, but already concluded rounds, should fail - vote.commitment.block_number = 10; - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); - vote.commitment.block_number = 11; - assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); - // no votes present - assert!(rounds.rounds.is_empty()); - - // add vote for active round 12 - vote.commitment.block_number = 12; - assert_eq!(rounds.add_vote(vote), VoteImportResult::Ok); - // good vote present - assert_eq!(rounds.rounds.len(), 1); - } - - #[test] - fn multiple_rounds() { - sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], - Default::default(), - ) - .unwrap(); - let validator_set_id = validators.id(); - - let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); - let commitment = Commitment { block_number: 1, payload, validator_set_id }; - let mut alice_vote = VoteMessage { - id: Keyring::Alice.public(), - commitment: commitment.clone(), - signature: Keyring::::Alice.sign(b"I am committed"), - }; - let mut bob_vote = VoteMessage { - id: Keyring::Bob.public(), - commitment: commitment.clone(), - signature: Keyring::::Bob.sign(b"I am committed"), - }; - let mut charlie_vote = VoteMessage { - id: Keyring::Charlie.public(), - commitment, - signature: Keyring::::Charlie.sign(b"I am committed"), - }; - let expected_signatures = vec![ - Some(Keyring::::Alice.sign(b"I am committed")), - Some(Keyring::::Bob.sign(b"I am committed")), - Some(Keyring::::Charlie.sign(b"I am committed")), - ]; - - // round 1 - only 2 out of 3 vote - assert_eq!(rounds.add_vote(alice_vote.clone()), VoteImportResult::Ok); - assert_eq!(rounds.add_vote(charlie_vote.clone()), VoteImportResult::Ok); - // should be 1 active round - assert_eq!(1, rounds.rounds.len()); - - // round 2 - only Charlie votes - charlie_vote.commitment.block_number = 2; - assert_eq!(rounds.add_vote(charlie_vote.clone()), VoteImportResult::Ok); - // should be 2 active rounds - assert_eq!(2, rounds.rounds.len()); - - // round 3 - all validators vote -> round is concluded - alice_vote.commitment.block_number = 3; - bob_vote.commitment.block_number = 3; - charlie_vote.commitment.block_number = 3; - assert_eq!(rounds.add_vote(alice_vote.clone()), VoteImportResult::Ok); - assert_eq!(rounds.add_vote(bob_vote.clone()), VoteImportResult::Ok); - assert_eq!( - rounds.add_vote(charlie_vote.clone()), - VoteImportResult::RoundConcluded(SignedCommitment { - commitment: charlie_vote.commitment, - signatures: expected_signatures - }) - ); - // should be only 2 active since this one auto-concluded - assert_eq!(2, rounds.rounds.len()); - - // conclude round 2 - rounds.conclude(2); - // should be no more active rounds since 2 was officially concluded and round "1" is stale - assert!(rounds.rounds.is_empty()); - - // conclude round 3 - rounds.conclude(3); - assert!(rounds.previous_votes.is_empty()); - } - - #[test] - fn should_provide_equivocation_proof() { - sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public()], - vec![Keyring::Alice.public(), Keyring::Bob.public()], - Default::default(), - ) - .unwrap(); - let validator_set_id = validators.id(); - let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![1, 1, 1, 1]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![2, 2, 2, 2]); - let commitment1 = Commitment { block_number: 1, payload: payload1, validator_set_id }; - let commitment2 = Commitment { block_number: 1, payload: payload2, validator_set_id }; - - let alice_vote1 = VoteMessage { - id: Keyring::Alice.public(), - commitment: commitment1, - signature: Keyring::::Alice.sign(b"I am committed"), - }; - let mut alice_vote2 = alice_vote1.clone(); - alice_vote2.commitment = commitment2; - - let expected_result = VoteImportResult::Equivocation(EquivocationProof { - first: alice_vote1.clone(), - second: alice_vote2.clone(), - }); - - // vote on one payload - ok - assert_eq!(rounds.add_vote(alice_vote1), VoteImportResult::Ok); - - // vote on _another_ commitment/payload -> expected equivocation proof - assert_eq!(rounds.add_vote(alice_vote2), expected_result); - } -} diff --git a/client/consensus/beefy-etf/src/tests.rs b/client/consensus/beefy-etf/src/tests.rs deleted file mode 100644 index 34bc8cd..0000000 --- a/client/consensus/beefy-etf/src/tests.rs +++ /dev/null @@ -1,1594 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Tests and test helpers for BEEFY. - -use crate::{ - aux_schema::{load_persistent, tests::verify_persisted_version}, - beefy_block_import_and_links, - communication::{ - gossip::{ - proofs_topic, tests::sign_commitment, votes_topic, GossipFilterCfg, GossipMessage, - GossipValidator, - }, - request_response::{on_demand_justifications_protocol_config, BeefyJustifsRequestHandler}, - }, - error::Error, - gossip_protocol_name, - justification::*, - wait_for_runtime_pallet, - worker::{PersistedState, VoterOracle}, - BeefyRPCLinks, BeefyVoterLinks, BeefyWorkerBuilder, KnownPeers, -}; -use futures::{future, stream::FuturesUnordered, Future, FutureExt, StreamExt}; -use parking_lot::Mutex; -use sc_block_builder::BlockBuilderBuilder; -use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; -use sc_consensus::{ - BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, - ImportedAux, -}; -use sc_network::{config::RequestResponseConfig, ProtocolName}; -use sc_network_test::{ - Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, - PeersFullClient, TestNetFactory, -}; -use sc_utils::notification::NotificationReceiver; -use serde::{Deserialize, Serialize}; -use sp_api::{ApiRef, ProvideRuntimeApi}; -use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; -use sp_consensus::BlockOrigin; -use sp_consensus_beefy_etf::{ - bls_crypto::{AuthorityId, Signature}, - known_payloads, - mmr::{find_mmr_root_digest, MmrRootProvider}, - test_utils::Keyring as BeefyKeyring, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, MmrRootHash, OpaqueKeyOwnershipProof, - Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, - BEEFY_ENGINE_ID, -}; -use sp_core::H256; -use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; -use sp_mmr_primitives::{Error as MmrError, MmrApi}; -use sp_runtime::{ - codec::{Decode, Encode}, - traits::{Header as HeaderT, NumberFor}, - BuildStorage, DigestItem, EncodedJustification, Justifications, Storage, -}; -use std::{marker::PhantomData, sync::Arc, task::Poll}; -use substrate_test_runtime_client::{BlockBuilderExt, ClientExt}; -use tokio::time::Duration; - -const GENESIS_HASH: H256 = H256::zero(); -pub(crate) fn beefy_gossip_proto_name() -> ProtocolName { - gossip_protocol_name(GENESIS_HASH, None) -} - -const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); -const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); -const ALTERNATE_BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x13); - -type BeefyBlockImport = crate::BeefyBlockImport< - Block, - substrate_test_runtime_client::Backend, - TestApi, - BlockImportAdapter, ->; - -pub(crate) type BeefyValidatorSet = ValidatorSet; -pub(crate) type BeefyPeer = Peer; - -#[derive(Debug, Serialize, Deserialize)] -struct Genesis(std::collections::BTreeMap); -impl BuildStorage for Genesis { - fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { - storage - .top - .extend(self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes()))); - Ok(()) - } -} - -#[derive(Default)] -pub(crate) struct PeerData { - 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, - pub beefy_genesis: NumberFor, -} - -impl BeefyTestNet { - pub(crate) fn new(n_authority: usize) -> Self { - let beefy_genesis = 1; - let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority), beefy_genesis }; - - for i in 0..n_authority { - let (rx, cfg) = on_demand_justifications_protocol_config(GENESIS_HASH, None); - let justif_protocol_name = cfg.name.clone(); - - net.add_authority_peer(vec![cfg]); - - let client = net.peers[i].client().as_client(); - let justif_handler = BeefyJustifsRequestHandler { - request_receiver: rx, - justif_protocol_name, - client, - _block: PhantomData, - metrics: None, - }; - *net.peers[i].data.beefy_justif_req_handler.lock() = Some(justif_handler); - } - net - } - - pub(crate) fn add_authority_peer(&mut self, req_resp_cfgs: Vec) { - self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![beefy_gossip_proto_name()], - request_response_protocols: req_resp_cfgs, - is_authority: true, - ..Default::default() - }); - } - - /// Builds the blocks and returns the vector of built block hashes. - /// Returned vector contains the genesis hash which allows for easy indexing (block number is - /// equal to index) - pub(crate) async fn generate_blocks_and_sync( - &mut self, - count: usize, - session_length: u64, - validator_set: &BeefyValidatorSet, - include_mmr_digest: bool, - ) -> Vec { - let mut all_hashes = Vec::with_capacity(count + 1); - - // make sure genesis is the only block in network, so we can insert genesis at the beginning - // of hashes, otherwise indexing would be broken - assert!(self.peer(0).client().as_backend().blockchain().hash(1).unwrap().is_none()); - - // push genesis to make indexing human readable (index equals to block number) - all_hashes.push(self.peer(0).client().info().genesis_hash); - - let mut block_num: NumberFor = self.peer(0).client().info().best_number; - let built_hashes = self.peer(0).generate_blocks(count, BlockOrigin::File, |mut builder| { - block_num = block_num.saturating_add(1).try_into().unwrap(); - if include_mmr_digest { - let num_byte = block_num.to_le_bytes().into_iter().next().unwrap(); - let mmr_root = MmrRootHash::repeat_byte(num_byte); - add_mmr_digest(&mut builder, mmr_root); - } - - if block_num % session_length == 0 { - add_auth_change_digest(&mut builder, validator_set.clone()); - } - - let block = builder.build().unwrap().block; - assert_eq!(block.header.number, block_num); - - block - }); - all_hashes.extend(built_hashes); - self.run_until_sync().await; - - all_hashes - } -} - -impl TestNetFactory for BeefyTestNet { - type Verifier = PassThroughVerifier; - type BlockImport = BeefyBlockImport; - type PeerData = PeerData; - - fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { - PassThroughVerifier::new(false) // use non-instant finality. - } - - fn make_block_import( - &self, - client: PeersClient, - ) -> ( - BlockImportAdapter, - Option>, - Self::PeerData, - ) { - let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = - ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let api = Arc::new(TestApi::new(self.beefy_genesis, &validator_set, GOOD_MMR_ROOT)); - let inner = BlockImportAdapter::new(client.clone()); - let (block_import, voter_links, rpc_links) = - beefy_block_import_and_links(inner, client.as_backend(), api, None); - let peer_data = PeerData { - beefy_rpc_links: Mutex::new(Some(rpc_links)), - beefy_voter_links: Mutex::new(Some(voter_links)), - ..Default::default() - }; - (BlockImportAdapter::new(block_import), None, peer_data) - } - - fn peer(&mut self, i: usize) -> &mut BeefyPeer { - &mut self.peers[i] - } - - fn peers(&self) -> &Vec { - &self.peers - } - - fn peers_mut(&mut self) -> &mut Vec { - &mut self.peers - } - - fn mut_peers)>(&mut self, closure: F) { - closure(&mut self.peers); - } - - fn add_full_peer(&mut self) { - // `add_authority_peer()` used instead. - unimplemented!() - } -} - -#[derive(Clone)] -pub(crate) struct TestApi { - pub beefy_genesis: u64, - pub validator_set: Option, - pub mmr_root_hash: MmrRootHash, - pub reported_equivocations: - Option, AuthorityId, Signature>>>>>, -} - -impl TestApi { - pub fn new( - beefy_genesis: u64, - validator_set: &BeefyValidatorSet, - mmr_root_hash: MmrRootHash, - ) -> Self { - TestApi { - beefy_genesis, - validator_set: Some(validator_set.clone()), - mmr_root_hash, - reported_equivocations: None, - } - } - - pub fn with_validator_set(validator_set: &BeefyValidatorSet) -> Self { - TestApi { - beefy_genesis: 1, - validator_set: Some(validator_set.clone()), - mmr_root_hash: GOOD_MMR_ROOT, - reported_equivocations: None, - } - } - - pub fn allow_equivocations(&mut self) { - self.reported_equivocations = Some(Arc::new(Mutex::new(vec![]))); - } -} - -// compiler gets confused and warns us about unused inner -#[allow(dead_code)] -pub(crate) struct RuntimeApi { - inner: TestApi, -} - -impl ProvideRuntimeApi for TestApi { - type Api = RuntimeApi; - fn runtime_api(&self) -> ApiRef { - RuntimeApi { inner: self.clone() }.into() - } -} -sp_api::mock_impl_runtime_apis! { - impl BeefyApi for RuntimeApi { - fn beefy_genesis() -> Option> { - Some(self.inner.beefy_genesis) - } - - fn validator_set() -> Option { - self.inner.validator_set.clone() - } - - fn submit_report_equivocation_unsigned_extrinsic( - proof: EquivocationProof, AuthorityId, Signature>, - _dummy: OpaqueKeyOwnershipProof, - ) -> Option<()> { - if let Some(equivocations_buf) = self.inner.reported_equivocations.as_ref() { - equivocations_buf.lock().push(proof); - None - } else { - panic!("Equivocations not expected, but following proof was reported: {:?}", proof); - } - } - - fn generate_key_ownership_proof( - _dummy1: ValidatorSetId, - _dummy2: AuthorityId, - ) -> Option { Some(OpaqueKeyOwnershipProof::new(vec![])) } - - fn read_share(_who: AuthorityId) -> Option> { - None - } - - fn read_commitment(_who: AuthorityId) -> Option { - None - } - } - - impl MmrApi> for RuntimeApi { - fn mmr_root() -> Result { - Ok(self.inner.mmr_root_hash) - } - } -} - -fn add_mmr_digest(builder: &mut impl BlockBuilderExt, mmr_hash: MmrRootHash) { - builder - .push_deposit_log_digest_item(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_hash).encode(), - )) - .unwrap(); -} - -fn add_auth_change_digest(builder: &mut impl BlockBuilderExt, new_auth_set: BeefyValidatorSet) { - builder - .push_deposit_log_digest_item(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::AuthoritiesChange(new_auth_set).encode(), - )) - .unwrap(); -} - -pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { - keys.iter().map(|key| key.public().into()).collect() -} - -pub(crate) fn create_beefy_keystore(authority: &BeefyKeyring) -> KeystorePtr { - let keystore = MemoryKeystore::new(); - keystore - .bls381_generate_new(BEEFY_KEY_TYPE, Some(&authority.to_seed())) - .expect("Creates authority key"); - keystore.into() -} - -async fn voter_init_setup( - net: &mut BeefyTestNet, - finality: &mut futures::stream::Fuse>, - api: &TestApi, -) -> Result, Error> { - let backend = net.peer(0).client().as_backend(); - let (beefy_genesis, best_grandpa) = wait_for_runtime_pallet(api, finality).await.unwrap(); - let key_store = None.into(); - let metrics = None; - BeefyWorkerBuilder::load_or_init_state( - beefy_genesis, - best_grandpa, - 1, - backend, - Arc::new(api.clone()), - &key_store, - &metrics, - ) - .await -} - -// Spawns beefy voters. Returns a future to spawn on the runtime. -fn initialize_beefy( - net: &mut BeefyTestNet, - peers: Vec<(usize, &BeefyKeyring, Arc)>, - min_block_delta: u32, -) -> impl Future -where - API: ProvideRuntimeApi + Sync + Send, - API::Api: BeefyApi + MmrApi>, -{ - let tasks = FuturesUnordered::new(); - - let mut notification_services = peers - .iter() - .map(|(peer_id, _, _)| { - let peer = &mut net.peers[*peer_id]; - (*peer_id, peer.take_notification_service(&beefy_gossip_proto_name()).unwrap()) - }) - .collect::>(); - - for (peer_id, key, api) in peers.into_iter() { - let peer = &net.peers[peer_id]; - - let keystore = create_beefy_keystore(key); - - let (_, _, peer_data) = net.make_block_import(peer.client().clone()); - let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; - - let beefy_voter_links = beefy_voter_links.lock().take(); - *peer.data.beefy_rpc_links.lock() = beefy_rpc_links.lock().take(); - *peer.data.beefy_voter_links.lock() = beefy_voter_links.clone(); - - let on_demand_justif_handler = peer.data.beefy_justif_req_handler.lock().take().unwrap(); - - let network_params = crate::BeefyNetworkParams { - network: peer.network_service().clone(), - sync: peer.sync_service().clone(), - notification_service: notification_services.remove(&peer_id).unwrap(), - gossip_protocol_name: beefy_gossip_proto_name(), - justifications_protocol_name: on_demand_justif_handler.protocol_name(), - _phantom: PhantomData, - }; - let payload_provider = MmrRootProvider::new(api.clone()); - - let beefy_params = crate::BeefyParams { - client: peer.client().as_client(), - backend: peer.client().as_backend(), - payload_provider, - runtime: api.clone(), - key_store: Some(keystore), - network_params, - links: beefy_voter_links.unwrap(), - min_block_delta, - prometheus_registry: None, - on_demand_justifications_handler: on_demand_justif_handler, - }; - let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); - - fn assert_send(_: &T) {} - assert_send(&task); - tasks.push(task); - } - - tasks.for_each(|_| async move {}) -} - -async fn run_until(future: impl Future + Unpin, net: &Arc>) { - let drive_to_completion = futures::future::poll_fn(|cx| { - net.lock().poll(cx); - Poll::<()>::Pending - }); - let _ = future::select(future, drive_to_completion).await; -} - -async fn run_for(duration: Duration, net: &Arc>) { - run_until(Box::pin(tokio::time::sleep(duration)), net).await; -} - -pub(crate) fn get_beefy_streams( - net: &mut BeefyTestNet, - // peer index and key - peers: impl Iterator)>, -) -> (Vec>, Vec>>) -{ - let mut best_block_streams = Vec::new(); - let mut versioned_finality_proof_streams = Vec::new(); - peers.for_each(|(index, _)| { - let beefy_rpc_links = net.peer(index).data.beefy_rpc_links.lock().clone().unwrap(); - let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } = - beefy_rpc_links; - best_block_streams.push(from_voter_best_beefy_stream.subscribe(100_000)); - versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe(100_000)); - }); - (best_block_streams, versioned_finality_proof_streams) -} - -async fn wait_for_best_beefy_blocks( - streams: Vec>, - net: &Arc>, - expected_beefy_blocks: &[u64], -) { - let mut wait_for = Vec::new(); - let len = expected_beefy_blocks.len(); - streams.into_iter().enumerate().for_each(|(i, stream)| { - let mut expected = expected_beefy_blocks.iter(); - wait_for.push(Box::pin(stream.take(len).for_each(move |best_beefy_hash| { - let expected = expected.next(); - async move { - let header = - net.lock().peer(i).client().as_client().expect_header(best_beefy_hash).unwrap(); - let best_beefy = *header.number(); - - assert_eq!(expected, Some(best_beefy).as_ref()); - } - }))); - }); - let wait_for = futures::future::join_all(wait_for); - run_until(wait_for, net).await; -} - -async fn wait_for_beefy_signed_commitments( - streams: Vec>>, - net: &Arc>, - expected_commitment_block_nums: &[u64], -) { - let mut wait_for = Vec::new(); - let len = expected_commitment_block_nums.len(); - streams.into_iter().for_each(|stream| { - let mut expected = expected_commitment_block_nums.iter(); - wait_for.push(Box::pin(stream.take(len).for_each(move |versioned_finality_proof| { - let expected = expected.next(); - async move { - let signed_commitment = match versioned_finality_proof { - sp_consensus_beefy_etf::VersionedFinalityProof::V1(sc) => sc, - }; - let commitment_block_num = signed_commitment.commitment.block_number; - assert_eq!(expected, Some(commitment_block_num).as_ref()); - // TODO: also verify commitment payload, validator set id, and signatures. - } - }))); - }); - let wait_for = futures::future::join_all(wait_for); - run_until(wait_for, net).await; -} - -async fn streams_empty_after_future( - streams: Vec>, - future: Option, -) where - T: std::fmt::Debug, - T: std::cmp::PartialEq, -{ - if let Some(future) = future { - future.await; - } - for mut stream in streams.into_iter() { - future::poll_fn(move |cx| { - assert_eq!(stream.poll_next_unpin(cx), Poll::Pending); - Poll::Ready(()) - }) - .await; - } -} - -async fn streams_empty_after_timeout( - streams: Vec>, - net: &Arc>, - timeout: Option, -) where - T: std::fmt::Debug, - T: std::cmp::PartialEq, -{ - let timeout = timeout.map(|timeout| Box::pin(run_for(timeout, net))); - streams_empty_after_future(streams, timeout).await; -} - -async fn finalize_block_and_wait_for_beefy( - net: &Arc>, - // peer index and key - peers: impl Iterator)> + Clone, - finalize_target: &H256, - expected_beefy: &[u64], -) { - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - - peers.clone().for_each(|(index, _)| { - let client = net.lock().peer(index).client().as_client(); - client.finalize_block(*finalize_target, None).unwrap(); - }); - - if expected_beefy.is_empty() { - // run for quarter second then verify no new best beefy block available - let timeout = Some(Duration::from_millis(250)); - streams_empty_after_timeout(best_blocks, &net, timeout).await; - streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - } else { - // run until expected beefy blocks are received - wait_for_best_beefy_blocks(best_blocks, &net, expected_beefy).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, expected_beefy).await; - } -} - -#[tokio::test] -async fn beefy_finalizing_blocks() { - sp_tracing::try_init_simple(); - - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = - ValidatorSet::new(make_beefy_ids(&peers), make_beefy_ids(&peers), 0).unwrap(); - let session_len = 10; - let min_block_delta = 4; - - let mut net = BeefyTestNet::new(2); - - let api = Arc::new(TestApi::with_validator_set(&validator_set)); - 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)); - - // push 42 blocks including `AuthorityChange` digests every 10 blocks. - let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; - - let net = Arc::new(Mutex::new(net)); - - // Minimum BEEFY block delta is 4. - - let peers = peers.into_iter().enumerate(); - // finalize block #5 -> BEEFY should finalize #1 (mandatory) and #5 from diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[5], &[5]).await; - - // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[10], &[10]).await; - - // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[18], &[14, 18]).await; - - // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[20], &[20]).await; - - // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 - finalize_block_and_wait_for_beefy(&net, peers, &hashes[21], &[]).await; -} - -#[tokio::test] -async fn lagging_validators() { - sp_tracing::try_init_simple(); - - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; - let validator_set = - ValidatorSet::new(make_beefy_ids(&peers), make_beefy_ids(&peers), 0).unwrap(); - let session_len = 30; - let min_block_delta = 1; - - let mut net = BeefyTestNet::new(3); - let api = Arc::new(TestApi::with_validator_set(&validator_set)); - 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)); - - // push 62 blocks including `AuthorityChange` digests every 30 blocks. - let hashes = net.generate_blocks_and_sync(62, session_len, &validator_set, true).await; - - let net = Arc::new(Mutex::new(net)); - - let peers = peers.into_iter().enumerate(); - // finalize block #15 -> BEEFY should finalize #1 (mandatory) and #9, #13, #14, #15 from - // diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[15], &[9, 13, 14, 15]).await; - - // Alice and Bob finalize #25, Charlie lags behind - let finalize = hashes[25]; - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - // verify nothing gets finalized by BEEFY - let timeout = Some(Duration::from_millis(100)); - streams_empty_after_timeout(best_blocks, &net, timeout).await; - streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - - // Charlie catches up and also finalizes #25 - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); - // expected beefy finalizes blocks 23, 24, 25 from diff-power-of-two - wait_for_best_beefy_blocks(best_blocks, &net, &[23, 24, 25]).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[23, 24, 25]).await; - - // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[30], &[30]).await; - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[32], &[31, 32]).await; - - // Verify that session-boundary votes get buffered by client and only processed once - // session-boundary block is GRANDPA-finalized (this guarantees authenticity for the new session - // validator set). - - // Alice and Bob finalize session-boundary mandatory block #60, Charlie lags behind - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - let finalize = hashes[60]; - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - // verify nothing gets finalized by BEEFY - let timeout = Some(Duration::from_millis(100)); - streams_empty_after_timeout(best_blocks, &net, timeout).await; - streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - - // Charlie catches up and also finalizes #60 (and should have buffered Alice's vote on #60) - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); - net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); - // verify beefy skips intermediary votes, and successfully finalizes mandatory block #60 - wait_for_best_beefy_blocks(best_blocks, &net, &[60]).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[60]).await; -} - -#[tokio::test] -async fn correct_beefy_payload() { - sp_tracing::try_init_simple(); - - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; - let validator_set = - ValidatorSet::new(make_beefy_ids(&peers), make_beefy_ids(&peers), 0).unwrap(); - let session_len = 20; - let min_block_delta = 2; - - let mut net = BeefyTestNet::new(4); - - // Alice, Bob, Charlie will vote on good payloads - let good_api = Arc::new(TestApi::new(1, &validator_set, GOOD_MMR_ROOT)); - let good_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie] - .iter() - .enumerate() - .map(|(id, key)| (id, key, good_api.clone())) - .collect(); - tokio::spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); - - // Dave will vote on bad mmr roots - let bad_api = Arc::new(TestApi::new(1, &validator_set, BAD_MMR_ROOT)); - let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; - tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); - - // push 12 blocks - let hashes = net.generate_blocks_and_sync(12, session_len, &validator_set, false).await; - - let net = Arc::new(Mutex::new(net)); - let peers = peers.into_iter().enumerate(); - // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; - finalize_block_and_wait_for_beefy(&net, peers, &hashes[10], &[9]).await; - - let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); - - // now 2 good validators and 1 bad one are voting - let hashof11 = hashes[11]; - net.lock().peer(0).client().as_client().finalize_block(hashof11, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(hashof11, None).unwrap(); - net.lock().peer(3).client().as_client().finalize_block(hashof11, None).unwrap(); - - // verify consensus is _not_ reached - let timeout = Some(Duration::from_millis(100)); - streams_empty_after_timeout(best_blocks, &net, timeout).await; - streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - - // 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()); - net.lock().peer(2).client().as_client().finalize_block(hashof11, None).unwrap(); - - // verify consensus is reached - wait_for_best_beefy_blocks(best_blocks, &net, &[11]).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[11]).await; -} - -#[tokio::test] -async fn beefy_importing_justifications() { - use futures::{future::poll_fn, task::Poll}; - use sc_client_api::BlockBackend; - - sp_tracing::try_init_simple(); - - let mut net = BeefyTestNet::new(2); - let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let good_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - // Set BEEFY genesis to block 3. - net.beefy_genesis = 3; - - let client = net.peer(0).client().clone(); - let full_client = client.as_client(); - let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); - let PeerData { beefy_voter_links, .. } = peer_data; - let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; - let mut justif_recv = justif_stream.subscribe(100_000); - - let params = |block: Block, justifications: Option| { - let mut import = BlockImportParams::new(BlockOrigin::File, block.header); - import.justifications = justifications; - import.body = Some(block.extrinsics); - import.finalized = true; - import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - import - }; - let backend_justif_for = |block_hash: H256| -> Option { - full_client - .justifications(block_hash) - .unwrap() - .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()) - }; - - let builder = BlockBuilderBuilder::new(&*full_client) - .on_parent_block(full_client.genesis_hash()) - .with_parent_block_number(0) - .build() - .unwrap(); - let block = builder.build().unwrap().block; - let hashof1 = block.header.hash(); - - // Import block 1 without justifications. - assert_eq!( - block_import.import_block(params(block.clone(), None)).await.unwrap(), - ImportResult::Imported(ImportedAux { is_new_best: true, ..Default::default() }), - ); - assert_eq!( - block_import.import_block(params(block, None)).await.unwrap(), - ImportResult::AlreadyInChain, - ); - - // Import block 2 with "valid" justification (beefy pallet genesis block not yet reached). - let block_num = 2; - let builder = BlockBuilderBuilder::new(&*full_client) - .on_parent_block(hashof1) - .with_parent_block_number(1) - .build() - .unwrap(); - let block = builder.build().unwrap().block; - let hashof2 = block.header.hash(); - - let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); - let encoded = versioned_proof.encode(); - let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); - assert_eq!( - block_import.import_block(params(block, justif)).await.unwrap(), - ImportResult::Imported(ImportedAux { - bad_justification: false, - is_new_best: true, - ..Default::default() - }), - ); - - // Verify no BEEFY justifications present (for either block 1 or 2): - { - // none in backend, - assert_eq!(backend_justif_for(hashof1), None); - assert_eq!(backend_justif_for(hashof2), None); - // and none sent to BEEFY worker. - poll_fn(move |cx| { - assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); - Poll::Ready(()) - }) - .await; - } - - // Import block 3 with valid justification. - let block_num = 3; - let builder = BlockBuilderBuilder::new(&*full_client) - .on_parent_block(hashof2) - .with_parent_block_number(2) - .build() - .unwrap(); - let block = builder.build().unwrap().block; - let hashof3 = block.header.hash(); - let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); - let encoded = versioned_proof.encode(); - let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); - let mut justif_recv = justif_stream.subscribe(100_000); - assert_eq!( - block_import.import_block(params(block, justif)).await.unwrap(), - ImportResult::Imported(ImportedAux { - bad_justification: false, - is_new_best: true, - ..Default::default() - }), - ); - // Verify BEEFY justification successfully imported: - { - // still not in backend (worker is responsible for appending to backend), - assert_eq!(backend_justif_for(hashof3), None); - // but sent to BEEFY worker - // (worker will append it to backend when all previous mandatory justifs are there as well). - poll_fn(move |cx| { - match justif_recv.poll_next_unpin(cx) { - Poll::Ready(Some(_justification)) => (), - v => panic!("unexpected value: {:?}", v), - } - Poll::Ready(()) - }) - .await; - } - - // Import block 4 with invalid justification (incorrect validator set). - let block_num = 4; - let builder = BlockBuilderBuilder::new(&*full_client) - .on_parent_block(hashof3) - .with_parent_block_number(3) - .build() - .unwrap(); - let block = builder.build().unwrap().block; - let hashof4 = block.header.hash(); - let keys = &[BeefyKeyring::Alice]; - let bad_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 1).unwrap(); - let proof = crate::justification::tests::new_finality_proof(block_num, &bad_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); - let encoded = versioned_proof.encode(); - let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); - let mut justif_recv = justif_stream.subscribe(100_000); - assert_eq!( - block_import.import_block(params(block, justif)).await.unwrap(), - ImportResult::Imported(ImportedAux { - // Still `false` because we don't want to fail import on bad BEEFY justifications. - bad_justification: false, - is_new_best: true, - ..Default::default() - }), - ); - // Verify bad BEEFY justifications was not imported: - { - // none in backend, - assert_eq!(backend_justif_for(hashof4), None); - // and none sent to BEEFY worker. - poll_fn(move |cx| { - assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); - Poll::Ready(()) - }) - .await; - } -} - -#[tokio::test] -async fn on_demand_beefy_justification_sync() { - 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), make_beefy_ids(&all_peers), 0).unwrap(); - let session_len = 5; - let min_block_delta = 4; - - let mut net = BeefyTestNet::new(4); - - // Alice, Bob, Charlie start first and make progress through voting. - let api = Arc::new(TestApi::with_validator_set(&validator_set)); - let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::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)); - - // 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)]; - // Instantiate but don't run Dave, yet. - let dave_task = initialize_beefy(&mut net, dave, min_block_delta); - let dave_index = 3; - - // push 30 blocks - let mut hashes = net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; - - let fast_peers = fast_peers.into_iter().enumerate(); - let net = Arc::new(Mutex::new(net)); - // With 3 active voters and one inactive, consensus should happen and blocks BEEFY-finalized. - // Need to finalize at least one block in each session, choose randomly. - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[1], &[1]).await; - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[6], &[5]).await; - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[10], &[10]).await; - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[17], &[15]).await; - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[24], &[20]).await; - - // Spawn Dave, they are now way behind voting and can only catch up through on-demand justif - // sync. - tokio::spawn(dave_task); - // Dave pushes and syncs 4 more blocks just to make sure he gets included in gossip. - { - let mut net_guard = net.lock(); - let built_hashes = - net_guard - .peer(dave_index) - .generate_blocks(4, BlockOrigin::File, |builder| builder.build().unwrap().block); - hashes.extend(built_hashes); - net_guard.run_until_sync().await; - } - - let (dave_best_blocks, _) = - get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::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, - run_for(Duration::from_millis(100), &net).await; - // freshly spun up Dave now needs to listen for gossip to figure out the state of their peers. - - // Have the other peers do some gossip so Dave finds out about their progress. - finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[25], &[25]).await; - finalize_block_and_wait_for_beefy(&net, fast_peers, &hashes[29], &[29]).await; - - // Kick Dave's async loop by finalizing another block. - client.finalize_block(hashes[2], None).unwrap(); - - // And verify Dave successfully finalized #1 (through on-demand justification request). - wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await; - - // Give all tasks some cpu cycles to burn through their events queues, - run_for(Duration::from_millis(100), &net).await; - // then verify Dave catches up through on-demand justification requests. - let (dave_best_blocks, _) = - get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); - client.finalize_block(hashes[6], None).unwrap(); - client.finalize_block(hashes[10], None).unwrap(); - client.finalize_block(hashes[17], None).unwrap(); - client.finalize_block(hashes[24], None).unwrap(); - client.finalize_block(hashes[26], None).unwrap(); - wait_for_best_beefy_blocks(dave_best_blocks, &net, &[5, 10, 15, 20, 25]).await; -} - -#[tokio::test] -async fn should_initialize_voter_at_genesis() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - - // push 15 blocks with `AuthorityChange` digests every 10 blocks - let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - // finalize 13 without justifications - net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - - let api = TestApi::with_validator_set(&validator_set); - // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // Test initialization at session boundary. - // verify voter initialized with two sessions starting at blocks 1 and 10 - let sessions = persisted_state.voting_oracle().sessions(); - assert_eq!(sessions.len(), 2); - assert_eq!(sessions[0].session_start(), 1); - assert_eq!(sessions[1].session_start(), 10); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), 1); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 1 - assert_eq!(persisted_state.best_beefy(), 0); - assert_eq!(persisted_state.best_grandpa_number(), 13); - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(13)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); -} - -#[tokio::test] -async fn should_initialize_voter_at_custom_genesis() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - // custom pallet genesis is block number 7 - let custom_pallet_genesis = 7; - let api = TestApi::new(custom_pallet_genesis, &validator_set, GOOD_MMR_ROOT); - - // push 15 blocks with `AuthorityChange` digests every 15 blocks - let hashes = net.generate_blocks_and_sync(15, 15, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - // finalize 3, 5, 8 without justifications - net.peer(0).client().as_client().finalize_block(hashes[3], None).unwrap(); - net.peer(0).client().as_client().finalize_block(hashes[5], None).unwrap(); - net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); - - // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // Test initialization at session boundary. - // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) - let sessions = persisted_state.voting_oracle().sessions(); - assert_eq!(sessions.len(), 1); - assert_eq!(sessions[0].session_start(), custom_pallet_genesis); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), custom_pallet_genesis); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 7 - assert_eq!(persisted_state.best_beefy(), 0); - assert_eq!(persisted_state.best_grandpa_number(), 8); - // we make this change since the BeefyWorker vote on top of every grandpa block currently - // keeping the original as we intend to modify this later - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(8)); - // assert_eq!(persisted_state.voting_oracle().voting_target(), Some(custom_pallet_genesis)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); - - // now re-init after genesis changes - - // should ignore existing aux db state and reinit at new genesis - let new_validator_set = - ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 42).unwrap(); - let new_pallet_genesis = 10; - let api = TestApi::new(new_pallet_genesis, &new_validator_set, GOOD_MMR_ROOT); - - net.peer(0).client().as_client().finalize_block(hashes[10], None).unwrap(); - // load persistent state - state preset in DB, but with different pallet genesis - let new_persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // verify voter initialized with single session starting at block `new_pallet_genesis` (10) - let sessions = new_persisted_state.voting_oracle().sessions(); - assert_eq!(sessions.len(), 1); - assert_eq!(sessions[0].session_start(), new_pallet_genesis); - let rounds = new_persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), new_pallet_genesis); - assert_eq!(rounds.validator_set_id(), new_validator_set.id()); - - // verify next vote target is mandatory block 10 - assert_eq!(new_persisted_state.best_beefy(), 0); - assert_eq!(new_persisted_state.best_grandpa_number(), 10); - assert_eq!(new_persisted_state.voting_oracle().voting_target(), Some(new_pallet_genesis)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, new_persisted_state); -} - -#[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), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - - // push 15 blocks with `AuthorityChange` digests every 10 blocks - let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - - // finalize 13 without justifications - net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - - // import/append BEEFY justification for session boundary block 10 - let commitment = Commitment { - payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), - block_number: 10, - validator_set_id: validator_set.id(), - }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { - commitment, - signatures: vec![None], - }); - backend - .append_justification(hashes[10], (BEEFY_ENGINE_ID, justif.encode())) - .unwrap(); - - // Test corner-case where session boundary == last beefy finalized, - // expect rounds initialized at last beefy finalized 10. - - let api = TestApi::with_validator_set(&validator_set); - // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // verify voter initialized with single session starting at block 10 - assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), 10); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify block 10 is correctly marked as finalized - assert_eq!(persisted_state.best_beefy(), 10); - assert_eq!(persisted_state.best_grandpa_number(), 13); - // verify next vote target is diff-power-of-two block 12 -> no longer the case with - // modifications - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(13)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); -} - -#[tokio::test] -async fn should_initialize_voter_at_latest_finalized() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - - // push 15 blocks with `AuthorityChange` digests every 10 blocks - let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; - - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - - // finalize 13 without justifications - net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - - // import/append BEEFY justification for block 12 - let commitment = Commitment { - payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), - block_number: 12, - validator_set_id: validator_set.id(), - }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { - commitment, - signatures: vec![None], - }); - backend - .append_justification(hashes[12], (BEEFY_ENGINE_ID, justif.encode())) - .unwrap(); - - // Test initialization at last BEEFY finalized. - - let api = TestApi::with_validator_set(&validator_set); - // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // verify voter initialized with single session starting at block 12 - assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), 12); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is 13 - assert_eq!(persisted_state.best_beefy(), 12); - assert_eq!(persisted_state.best_grandpa_number(), 13); - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(13)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); -} - -#[tokio::test] -async fn should_initialize_voter_at_custom_genesis_when_state_unavailable() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - // custom pallet genesis is block number 7 - let custom_pallet_genesis = 7; - let mut api = TestApi::new(custom_pallet_genesis, &validator_set, GOOD_MMR_ROOT); - // remove validator set from `TestApi`, practically simulating unavailable/pruned runtime state - api.validator_set = None; - - // push 30 blocks with `AuthorityChange` digests every 5 blocks - let hashes = net.generate_blocks_and_sync(30, 5, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - // finalize 30 without justifications - net.peer(0).client().as_client().finalize_block(hashes[30], None).unwrap(); - - // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // Test initialization at session boundary. - // verify voter initialized with all sessions pending, first one starting at block 5 (start of - // session containing `custom_pallet_genesis`). - let sessions = persisted_state.voting_oracle().sessions(); - // should have enqueued 6 sessions (every 5 blocks from 5 to 30) - assert_eq!(sessions.len(), 6); - assert_eq!(sessions[0].session_start(), 7); - assert_eq!(sessions[1].session_start(), 10); - assert_eq!(sessions[2].session_start(), 15); - assert_eq!(sessions[3].session_start(), 20); - assert_eq!(sessions[4].session_start(), 25); - assert_eq!(sessions[5].session_start(), 30); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), custom_pallet_genesis); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 7 (genesis) - assert_eq!(persisted_state.best_beefy(), 0); - assert_eq!(persisted_state.best_grandpa_number(), 30); - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(30)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); -} - -#[tokio::test] -async fn should_catch_up_when_loading_saved_voter_state() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let backend = net.peer(0).client().as_backend(); - - // push 30 blocks with `AuthorityChange` digests every 10 blocks - let hashes = net.generate_blocks_and_sync(30, 10, &validator_set, false).await; - let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); - // finalize 13 without justifications - net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - - let api = TestApi::with_validator_set(&validator_set); - - // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // Test initialization at session boundary. - // verify voter initialized with two sessions starting at blocks 1 and 10 - let sessions = persisted_state.voting_oracle().sessions(); - assert_eq!(sessions.len(), 2); - assert_eq!(sessions[0].session_start(), 1); - assert_eq!(sessions[1].session_start(), 10); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), 1); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 1 - assert_eq!(persisted_state.best_beefy(), 0); - assert_eq!(persisted_state.best_grandpa_number(), 13); - // we changed this to 13 since we are voting on top of each finalized block - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(13)); - - // verify state also saved to db - assert!(verify_persisted_version(&*backend)); - let state = load_persistent(&*backend).unwrap().unwrap(); - assert_eq!(state, persisted_state); - - // now let's consider that the node goes offline, and then it restarts after a while - - // finalize 25 without justifications - net.peer(0).client().as_client().finalize_block(hashes[25], None).unwrap(); - // load persistent state - state preset in DB - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); - - // Verify voter initialized with old sessions plus a new one starting at block 20. - // There shouldn't be any duplicates. - let sessions = persisted_state.voting_oracle().sessions(); - assert_eq!(sessions.len(), 3); - assert_eq!(sessions[0].session_start(), 1); - assert_eq!(sessions[1].session_start(), 10); - assert_eq!(sessions[2].session_start(), 20); - let rounds = persisted_state.active_round().unwrap(); - assert_eq!(rounds.session_start(), 1); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - - // verify next vote target is mandatory block 1 - assert_eq!(persisted_state.best_beefy(), 0); - assert_eq!(persisted_state.best_grandpa_number(), 25); - assert_eq!(persisted_state.voting_oracle().voting_target(), Some(25)); -} - -#[tokio::test] -async fn beefy_finalizing_after_pallet_genesis() { - sp_tracing::try_init_simple(); - - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = - ValidatorSet::new(make_beefy_ids(&peers), make_beefy_ids(&peers), 14).unwrap(); - let session_len = 10; - let min_block_delta = 1; - let pallet_genesis = 15; - - let mut net = BeefyTestNet::new(2); - - let api = Arc::new(TestApi::new(pallet_genesis, &validator_set, GOOD_MMR_ROOT)); - 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)); - - // push 42 blocks including `AuthorityChange` digests every 10 blocks. - let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; - - let net = Arc::new(Mutex::new(net)); - let peers = peers.into_iter().enumerate(); - - // Minimum BEEFY block delta is 1. - - // GRANDPA finalize blocks leading up to BEEFY pallet genesis -> BEEFY should finalize nothing. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[14], &[]).await; - - // GRANDPA finalize block #16 -> BEEFY should finalize #15 (genesis mandatory) and #16. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[16], &[15, 16]).await; - - // GRANDPA finalize #21 -> BEEFY finalize #20 (mandatory) and #21 - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[21], &[20, 21]).await; -} - -// note to the reviewer: for the moment, equivocations do not work as intended. -// This is a consequence of the changes made to the beefy worker, where the worker -// signs a VoteMessage with an empty message payload. -// In the next phase of the protocol when we address interoperability, -// we will revisit this logic to complete the solution. -// for now, lack of equivocation reporting does not cause any negative side effects - -// #[tokio::test] -// async fn beefy_reports_equivocations() { -// sp_tracing::try_init_simple(); - -// let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; -// let validator_set = ValidatorSet::new(make_beefy_ids(&peers), make_beefy_ids(&peers), -// 0).unwrap(); let session_len = 10; -// let min_block_delta = 4; - -// let mut net = BeefyTestNet::new(3); - -// // Alice votes on good MMR roots, equivocations are allowed/expected. -// let mut api_alice = TestApi::with_validator_set(&validator_set); -// api_alice.allow_equivocations(); -// let api_alice = Arc::new(api_alice); -// let alice = (0, &BeefyKeyring::Alice, api_alice.clone()); -// tokio::spawn(initialize_beefy(&mut net, vec![alice], min_block_delta)); - -// // Bob votes on bad MMR roots, equivocations are allowed/expected. -// let mut api_bob = TestApi::new(1, &validator_set, BAD_MMR_ROOT); -// api_bob.allow_equivocations(); -// let api_bob = Arc::new(api_bob); -// let bob = (1, &BeefyKeyring::Bob, api_bob.clone()); -// tokio::spawn(initialize_beefy(&mut net, vec![bob], min_block_delta)); - -// // We spawn another node voting with Bob key, on alternate bad MMR roots (equivocating). -// // Equivocations are allowed/expected. -// let mut api_bob_prime = TestApi::new(1, &validator_set, ALTERNATE_BAD_MMR_ROOT); -// api_bob_prime.allow_equivocations(); -// let api_bob_prime = Arc::new(api_bob_prime); -// let bob_prime = (2, &BeefyKeyring::Bob, api_bob_prime.clone()); -// tokio::spawn(initialize_beefy(&mut net, vec![bob_prime], min_block_delta)); - -// // push 42 blocks including `AuthorityChange` digests every 10 blocks. -// let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, false).await; - -// let net = Arc::new(Mutex::new(net)); - -// // Minimum BEEFY block delta is 4. - -// let peers = peers.into_iter().enumerate(); -// // finalize block #1 -> BEEFY should not finalize anything (each node votes on different MMR). -// let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); -// peers.clone().for_each(|(index, _)| { -// let client = net.lock().peer(index).client().as_client(); -// client.finalize_block(hashes[1], None).unwrap(); -// }); - -// // run for up to 5 seconds waiting for Alice's report of Bob/Bob_Prime equivocation. -// for wait_ms in [250, 500, 1250, 3000] { -// run_for(Duration::from_millis(wait_ms), &net).await; -// if !api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty() { -// break -// } -// } - -// // Verify expected equivocation -// let alice_reported_equivocations = api_alice.reported_equivocations.as_ref().unwrap().lock(); -// assert_eq!(alice_reported_equivocations.len(), 1); -// let equivocation_proof = alice_reported_equivocations.get(0).unwrap(); -// assert_eq!(equivocation_proof.first.id, BeefyKeyring::Bob.public()); -// assert_eq!(equivocation_proof.first.commitment.block_number, 1); - -// // Verify neither Bob or Bob_Prime report themselves as equivocating. -// assert!(api_bob.reported_equivocations.as_ref().unwrap().lock().is_empty()); -// assert!(api_bob_prime.reported_equivocations.as_ref().unwrap().lock().is_empty()); - -// // sanity verify no new blocks have been finalized by BEEFY -// streams_empty_after_timeout(best_blocks, &net, None).await; -// streams_empty_after_timeout(versioned_finality_proof, &net, None).await; -// } - -#[tokio::test] -async fn gossipped_finality_proofs() { - sp_tracing::try_init_simple(); - - let validators = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; - // Only Alice and Bob are running the voter -> finality threshold not reached - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = - ValidatorSet::new(make_beefy_ids(&validators), make_beefy_ids(&validators), 0).unwrap(); - let session_len = 10; - let min_block_delta = 1; - - let mut net = BeefyTestNet::new(3); - let api = Arc::new(TestApi::with_validator_set(&validator_set)); - let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - - let charlie = &mut net.peers[2]; - let known_peers = Arc::new(Mutex::new(KnownPeers::::new())); - // Charlie will run just the gossip engine and not the full voter. - let (gossip_validator, _) = GossipValidator::new(known_peers); - let charlie_gossip_validator = Arc::new(gossip_validator); - charlie_gossip_validator.update_filter(GossipFilterCfg:: { - start: 1, - end: 10, - validator_set: &validator_set, - }); - let mut charlie_gossip_engine = sc_network_gossip::GossipEngine::new( - charlie.network_service().clone(), - charlie.sync_service().clone(), - charlie.take_notification_service(&beefy_gossip_proto_name()).unwrap(), - beefy_gossip_proto_name(), - charlie_gossip_validator.clone(), - None, - ); - - // Alice and Bob run full voter. - tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); - - let net = Arc::new(Mutex::new(net)); - - // push 42 blocks - let hashes = net.lock().generate_blocks_and_sync(42, session_len, &validator_set, true).await; - - let peers = peers.into_iter().enumerate(); - - // Alice, Bob and Charlie finalize #1, Alice and Bob vote on it, but not Charlie. - let finalize = hashes[1]; - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); - // verify nothing gets finalized by BEEFY - let timeout = Box::pin(tokio::time::sleep(Duration::from_millis(100))); - let pump_net = futures::future::poll_fn(|cx| { - net.lock().poll(cx); - Poll::<()>::Pending - }); - let pump_gossip = &mut charlie_gossip_engine; - let pump_with_timeout = future::select(pump_gossip, future::select(pump_net, timeout)); - streams_empty_after_future(best_blocks, Some(pump_with_timeout)).await; - streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - // Charlie gossips finality proof for #1 -> Alice and Bob also finalize. - let proof = crate::communication::gossip::tests::dummy_proof(1, &validator_set); - let gossip_proof = GossipMessage::::FinalityProof(proof); - let encoded_proof = gossip_proof.encode(); - charlie_gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); - // Expect #1 is finalized. - wait_for_best_beefy_blocks(best_blocks, &net, &[1]).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[1]).await; - - // Code above verifies gossipped finality proofs are correctly imported and consumed by voters. - // Next, let's verify finality proofs are correctly generated and gossipped by voters. - - // Everyone finalizes #2 - let block_number = 2u64; - let finalize = hashes[block_number as usize]; - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); - - // Simulate Charlie vote on #2 - let header = net.lock().peer(2).client().as_client().expect_header(finalize).unwrap(); - let mmr_root = find_mmr_root_digest::(&header).unwrap(); - let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, mmr_root.encode()); - let commitment = Commitment { payload, block_number, validator_set_id: validator_set.id() }; - let signature = sign_commitment(&BeefyKeyring::Charlie, &commitment); - let vote_message = VoteMessage { commitment, id: BeefyKeyring::Charlie.public(), signature }; - let encoded_vote = GossipMessage::::Vote(vote_message).encode(); - charlie_gossip_engine.gossip_message(votes_topic::(), encoded_vote, true); - - // Expect #2 is finalized. - wait_for_best_beefy_blocks(best_blocks, &net, &[2]).await; - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[2]).await; - - // Now verify Charlie also sees the gossipped proof generated by either Alice or Bob. - let mut charlie_gossip_proofs = Box::pin( - charlie_gossip_engine - .messages_for(proofs_topic::()) - .filter_map(|notification| async move { - GossipMessage::::decode(&mut ¬ification.message[..]).ok().and_then( - |message| match message { - GossipMessage::::Vote(_) => unreachable!(), - GossipMessage::::FinalityProof(proof) => Some(proof), - }, - ) - }) - .fuse(), - ); - loop { - let pump_net = futures::future::poll_fn(|cx| { - net.lock().poll(cx); - Poll::<()>::Pending - }); - let mut gossip_engine = &mut charlie_gossip_engine; - futures::select! { - // pump gossip engine - _ = gossip_engine => unreachable!(), - // pump network - _ = pump_net.fuse() => unreachable!(), - // verify finality proof has been gossipped - proof = charlie_gossip_proofs.next() => { - let proof = proof.unwrap(); - let (round, _) = proof_block_num_and_set_id::(&proof); - match round { - 1 => continue, // finality proof generated by Charlie in the previous round - 2 => break, // finality proof generated by Alice or Bob and gossiped to Charlie - _ => panic!("Charlie got unexpected finality proof"), - } - }, - } - } -} diff --git a/client/consensus/beefy-etf/src/worker.rs b/client/consensus/beefy-etf/src/worker.rs deleted file mode 100644 index eaa3ec7..0000000 --- a/client/consensus/beefy-etf/src/worker.rs +++ /dev/null @@ -1,1851 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - communication::{ - gossip::{proofs_topic, votes_topic, GossipFilterCfg, GossipMessage}, - peers::PeerReport, - request_response::outgoing_requests_engine::ResponseInfo, - }, - error::Error, - find_authorities_change, - justification::BeefyVersionedFinalityProof, - keystore::BeefyKeystore, - metric_inc, metric_set, - metrics::VoterMetrics, - round::{Rounds, VoteImportResult}, - BeefyComms, BeefyVoterLinks, LOG_TARGET, -}; -use codec::{Codec, Decode, DecodeAll, Encode}; -use futures::{stream::Fuse, FutureExt, StreamExt}; -use log::{debug, error, info, log_enabled, trace, warn}; -use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; -use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sc_utils::notification::NotificationReceiver; -use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; -use sp_consensus::SyncOracle; - -#[cfg(feature = "bls-experimental")] -use sp_consensus_beefy_etf::bls_crypto::{AuthorityId, Signature}; - -#[cfg(not(feature = "bls-experimental"))] -use sp_consensus_beefy_etf::ecdsa_crypto::{AuthorityId, Signature}; - -use sp_consensus_beefy_etf::{ - check_equivocation_proof, known_payloads, BeefyApi, BeefySignatureHasher, Commitment, - EquivocationProof, Payload, PayloadProvider, ValidatorSet, ValidatorSetId, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, -}; -use sp_runtime::{ - generic::BlockId, - traits::{Block, Header, NumberFor, Zero}, - SaturatedConversion, -}; -use std::{ - collections::{BTreeMap, BTreeSet, VecDeque}, - fmt::Debug, - sync::Arc, -}; - -/// Bound for the number of pending justifications - use 2400 - the max number -/// of justifications possible in a single session. -const MAX_BUFFERED_JUSTIFICATIONS: usize = 2400; - -pub(crate) enum RoundAction { - Drop, - Process, - Enqueue, -} - -/// Responsible for the voting strategy. -/// It chooses which incoming votes to accept and which votes to generate. -/// Keeps track of voting seen for current and future rounds. -/// -/// Note: this is part of `PersistedState` so any changes here should also bump -/// aux-db schema version. -#[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct VoterOracle { - /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. - /// - /// There are three voter states corresponding to three queue states: - /// 1. voter uninitialized: queue empty, - /// 2. up-to-date - all mandatory blocks leading up to current GRANDPA finalized: queue has ONE - /// element, the 'current session' where `mandatory_done == true`, - /// 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>, - /// Min delta in block numbers between two blocks, BEEFY should vote on. - min_block_delta: u32, - /// 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, -} - -impl VoterOracle { - /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. - pub fn checked_new( - sessions: VecDeque>, - min_block_delta: u32, - grandpa_header: ::Header, - best_beefy: NumberFor, - ) -> Option { - let mut prev_start = Zero::zero(); - let mut prev_validator_id = None; - // verifies the - let mut validate = || -> bool { - let best_grandpa = *grandpa_header.number(); - if sessions.is_empty() || best_beefy > best_grandpa { - return false; - } - for (idx, session) in sessions.iter().enumerate() { - let start = session.session_start(); - if session.validators().is_empty() { - return false; - } - if start > best_grandpa || start <= prev_start { - return false; - } - #[cfg(not(test))] - if let Some(prev_id) = prev_validator_id { - if session.validator_set_id() <= prev_id { - return false; - } - } - if idx != 0 && session.mandatory_done() { - return false; - } - prev_start = session.session_start(); - prev_validator_id = Some(session.validator_set_id()); - } - true - }; - if validate() { - Some(VoterOracle { - sessions, - // Always target at least one block better than current best beefy. - min_block_delta: min_block_delta.max(1), - best_grandpa_block_header: grandpa_header, - best_beefy_block: best_beefy, - }) - } else { - error!( - target: LOG_TARGET, - "🥩 Invalid sessions queue: {:?}; best-beefy {:?} best-grandpa-header {:?}.", - sessions, - best_beefy, - grandpa_header - ); - None - } - } - - // 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) -> Result<&Rounds, Error> { - self.sessions.front().ok_or(Error::UninitSession) - } - - // 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) -> Result<&mut Rounds, Error> { - self.sessions.front_mut().ok_or(Error::UninitSession) - } - - fn current_validator_set(&self) -> Result<&ValidatorSet, Error> { - self.active_rounds().map(|r| r.validator_set()) - } - - // Prune the sessions queue to keep the Oracle in one of the expected three states. - // - // To be called on each BEEFY finality and on each new rounds/session addition. - fn try_prune(&mut self) { - if self.sessions.len() > 1 { - // when there's multiple sessions, only keep the `!mandatory_done()` ones. - self.sessions.retain(|s| !s.mandatory_done()) - } - } - - /// Check if an observed session can be added to the Oracle. - pub fn can_add_session(&self, session_start: NumberFor) -> bool { - let latest_known_session_start = - self.sessions.back().map(|session| session.session_start()); - Some(session_start) > latest_known_session_start - } - - /// Add new observed session to the Oracle. - 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(); - } - - /// Finalize a particular block. - pub fn finalize(&mut self, block: NumberFor) -> Result<(), Error> { - // Conclude voting round for this block. - self.active_rounds_mut()?.conclude(block); - // Prune any now "finalized" sessions from queue. - self.try_prune(); - Ok(()) - } - - /// Return current pending mandatory block, if any, plus its active validator set. - pub fn mandatory_pending(&self) -> Option<(NumberFor, ValidatorSet)> { - self.sessions.front().and_then(|round| { - if round.mandatory_done() { - None - } else { - Some((round.session_start(), round.validator_set().clone())) - } - }) - } - - /// Return `(A, B)` tuple representing inclusive [A, B] interval of votes to accept. - pub fn accepted_interval(&self) -> Result<(NumberFor, NumberFor), Error> { - let rounds = self.sessions.front().ok_or(Error::UninitSession)?; - - if rounds.mandatory_done() { - // There's only one session active and its mandatory is done. - // Accept any vote for a GRANDPA finalized block in a better round. - Ok(( - rounds.session_start().max(self.best_beefy_block), - (*self.best_grandpa_block_header.number()), - )) - } else { - // Current session has mandatory not done. - // Only accept votes for the mandatory block in the front of queue. - Ok((rounds.session_start(), rounds.session_start())) - } - } - - /// Utility function to quickly decide what to do for each round. - pub fn triage_round(&self, round: NumberFor) -> Result { - let (start, end) = self.accepted_interval()?; - if start <= round && round <= end { - Ok(RoundAction::Process) - } else if round > end { - Ok(RoundAction::Enqueue) - } else { - Ok(RoundAction::Drop) - } - } - - /// Return `Some(number)` if we should be voting on block `number`, - /// return `None` if there is no block we should vote on. - #[cfg(not(feature = "bls-experimental"))] - pub fn voting_target(&self) -> Option> { - let rounds = self.sessions.front().or_else(|| { - info!(target: LOG_TARGET, "🥩 No voting round started"); - None - })?; - - let best_grandpa = *self.best_grandpa_block_header.number(); - let best_beefy = self.best_beefy_block; - - // `target` is guaranteed > `best_beefy` since `min_block_delta` is at least `1`. - let target = - vote_target(best_grandpa, best_beefy, rounds.session_start(), self.min_block_delta); - info!( - target: LOG_TARGET, - "🥩 best beefy: #{:?}, best finalized: #{:?}, current_vote_target: {:?}", - best_beefy, - best_grandpa, - target - ); - target - } - - /// if we are running etf, we vote on every grandpa block for now - #[cfg(feature = "bls-experimental")] - pub fn voting_target(&self) -> Option> { - let best_grandpa = *self.best_grandpa_block_header.number(); - Some(best_grandpa) - } -} - -/// BEEFY voter state persisted in aux DB. -/// -/// Note: Any changes here should also bump aux-db schema version. -#[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct PersistedState { - /// Best block we voted on. - best_voted: 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, - /// Pallet-beefy genesis block - block number when BEEFY consensus started for this chain. - pallet_genesis: NumberFor, -} - -impl PersistedState { - pub fn checked_new( - grandpa_header: ::Header, - best_beefy: NumberFor, - sessions: VecDeque>, - min_block_delta: u32, - pallet_genesis: NumberFor, - ) -> Option { - VoterOracle::checked_new(sessions, min_block_delta, grandpa_header, best_beefy).map( - |voting_oracle| PersistedState { - best_voted: Zero::zero(), - voting_oracle, - pallet_genesis, - }, - ) - } - - pub fn pallet_genesis(&self) -> NumberFor { - self.pallet_genesis - } - - pub(crate) fn set_min_block_delta(&mut self, min_block_delta: u32) { - self.voting_oracle.min_block_delta = min_block_delta.max(1); - } - - pub fn best_beefy(&self) -> NumberFor { - self.voting_oracle.best_beefy_block - } - - pub(crate) fn set_best_beefy(&mut self, best_beefy: NumberFor) { - self.voting_oracle.best_beefy_block = best_beefy; - } - - pub(crate) fn set_best_grandpa(&mut self, best_grandpa: ::Header) { - self.voting_oracle.best_grandpa_block_header = best_grandpa; - } - - pub fn voting_oracle(&self) -> &VoterOracle { - &self.voting_oracle - } - - pub(crate) fn gossip_filter_config(&self) -> Result, Error> { - let (start, end) = self.voting_oracle.accepted_interval()?; - let validator_set = self.voting_oracle.current_validator_set()?; - Ok(GossipFilterCfg { start, end, validator_set }) - } - - /// Handle session changes by starting new voting round for mandatory blocks. - pub fn init_session_at( - &mut self, - new_session_start: NumberFor, - validator_set: ValidatorSet, - key_store: &BeefyKeystore, - metrics: &Option, - ) { - debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); - - // BEEFY should finalize a mandatory block during each session. - if let Ok(active_session) = self.voting_oracle.active_rounds() { - if !active_session.mandatory_done() { - debug!( - target: LOG_TARGET, - "🥩 New session {} while active session {} is still lagging.", - validator_set.id(), - active_session.validator_set_id(), - ); - metric_inc!(metrics, beefy_lagging_sessions); - } - } - - if log_enabled!(target: LOG_TARGET, log::Level::Debug) { - // verify the new validator set - only do it if we're also logging the warning - if verify_validator_set::(&new_session_start, &validator_set, key_store).is_err() { - metric_inc!(metrics, beefy_no_authority_found_in_store); - } - } - - let id = validator_set.id(); - self.voting_oracle.add_session(Rounds::new(new_session_start, validator_set)); - metric_set!(metrics, beefy_validator_set_id, id); - info!( - target: LOG_TARGET, - "🥩 New Rounds for validator set id: {:?} with session_start {:?}", - id, - new_session_start - ); - } -} - -/// A BEEFY worker/voter that follows the BEEFY protocol -// TODO: fix warning: field `payload_provider` is never read -// and remove the #[allow(dead_code)] attribute -// https://github.com/ideal-lab5/idn-sdk/issues/63 -#[allow(dead_code)] -pub(crate) struct BeefyWorker { - // utilities - pub backend: Arc, - pub runtime: Arc, - pub key_store: BeefyKeystore, - pub payload_provider: P, - pub sync: Arc, - - // communication (created once, but returned and reused if worker is restarted/reinitialized) - pub comms: BeefyComms, - - // channels - /// Links between the block importer, the background voter and the RPC layer. - pub links: BeefyVoterLinks, - - // voter state - /// Buffer holding justifications for future processing. - pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, - /// Persisted voter state. - pub persisted_state: PersistedState, - /// BEEFY voter metrics - pub metrics: Option, - /// submit equivocations and pulses - pub offchain_tx_pool_factory: OffchainTransactionPoolFactory, -} - -// impl BeefyWorker -impl BeefyWorker -where - B: Block + Codec, - BE: Backend, - P: PayloadProvider, - S: SyncOracle, - R: ProvideRuntimeApi, - R::Api: BeefyApi, - // T: TransactionPool + LocalTransactionPool + 'static, -{ - fn best_grandpa_block(&self) -> NumberFor { - *self.persisted_state.voting_oracle.best_grandpa_block_header.number() - } - - fn voting_oracle(&self) -> &VoterOracle { - &self.persisted_state.voting_oracle - } - - #[cfg(test)] - fn active_rounds(&mut self) -> Result<&Rounds, Error> { - self.persisted_state.voting_oracle.active_rounds() - } - - /// Handle session changes by starting new voting round for mandatory blocks. - fn init_session_at( - &mut self, - validator_set: ValidatorSet, - new_session_start: NumberFor, - ) { - self.persisted_state.init_session_at( - new_session_start, - validator_set, - &self.key_store, - &self.metrics, - ); - } - - fn handle_finality_notification( - &mut self, - notification: &FinalityNotification, - ) -> Result<(), Error> { - let header = ¬ification.header; - debug!( - target: LOG_TARGET, - "🥩 Finality notification: header(number {:?}, hash {:?}) tree_route {:?}", - header.number(), - header.hash(), - notification.tree_route, - ); - - self.runtime - .runtime_api() - .beefy_genesis(header.hash()) - .ok() - .flatten() - .filter(|genesis| *genesis == self.persisted_state.pallet_genesis) - .ok_or(Error::ConsensusReset)?; - - let mut new_session_added = false; - if *header.number() > self.best_grandpa_block() { - // update best GRANDPA finalized block we have seen - self.persisted_state.set_best_grandpa(header.clone()); - - // Check all (newly) finalized blocks for new session(s). - let backend = self.backend.clone(); - for header in notification - .tree_route - .iter() - .map(|hash| { - backend - .blockchain() - .expect_header(*hash) - .expect("just finalized block should be available; qed.") - }) - .chain(std::iter::once(header.clone())) - { - if let Some(new_validator_set) = find_authorities_change::(&header) { - self.init_session_at(new_validator_set, *header.number()); - new_session_added = true; - } - } - - if new_session_added { - crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) - .map_err(|e| Error::Backend(e.to_string()))?; - } - - // Update gossip validator votes filter. - if let Err(e) = self - .persisted_state - .gossip_filter_config() - .map(|filter| self.comms.gossip_validator.update_filter(filter)) - { - error!(target: LOG_TARGET, "🥩 Voter error: {:?}", e); - } - } - - Ok(()) - } - - /// Based on [VoterOracle] this vote is either processed here or discarded. - fn triage_incoming_vote( - &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> Result<(), Error> { - let block_num = vote.commitment.block_number; - match self.voting_oracle().triage_round(block_num)? { - RoundAction::Process => - if let Some(finality_proof) = self.handle_vote(vote)? { - let gossip_proof = GossipMessage::::FinalityProof(finality_proof); - let encoded_proof = gossip_proof.encode(); - self.comms.gossip_engine.gossip_message( - proofs_topic::(), - encoded_proof, - true, - ); - }, - RoundAction::Drop => metric_inc!(self.metrics, beefy_stale_votes), - RoundAction::Enqueue => error!(target: LOG_TARGET, "🥩 unexpected vote: {:?}.", vote), - }; - Ok(()) - } - - /// Based on [VoterOracle] this justification is either processed here or enqueued for later. - /// - /// Expects `justification` to be valid. - fn triage_incoming_justif( - &mut self, - justification: BeefyVersionedFinalityProof, - ) -> Result<(), Error> { - let signed_commitment = match justification { - VersionedFinalityProof::V1(ref sc) => sc, - }; - let block_num = signed_commitment.commitment.block_number; - match self.voting_oracle().triage_round(block_num)? { - RoundAction::Process => { - debug!(target: LOG_TARGET, "🥩 Process justification for round: {:?}.", block_num); - metric_inc!(self.metrics, beefy_imported_justifications); - self.finalize(justification)? - }, - RoundAction::Enqueue => { - debug!(target: LOG_TARGET, "🥩 Buffer justification for round: {:?}.", block_num); - if self.pending_justifications.len() < MAX_BUFFERED_JUSTIFICATIONS { - self.pending_justifications.entry(block_num).or_insert(justification); - metric_inc!(self.metrics, beefy_buffered_justifications); - } else { - metric_inc!(self.metrics, beefy_buffered_justifications_dropped); - warn!( - target: LOG_TARGET, - "🥩 Buffer justification dropped for round: {:?}.", block_num - ); - } - }, - RoundAction::Drop => metric_inc!(self.metrics, beefy_stale_justifications), - }; - Ok(()) - } - - fn handle_vote( - &mut self, - vote: VoteMessage, AuthorityId, Signature>, - ) -> Result>, Error> { - let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; - - let block_number = vote.commitment.block_number; - match rounds.add_vote(vote) { - VoteImportResult::RoundConcluded(signed_commitment) => { - let finality_proof = VersionedFinalityProof::V1(signed_commitment); - debug!( - target: LOG_TARGET, - "🥩 Round #{} concluded, finality_proof: {:?}.", block_number, finality_proof - ); - // We created the `finality_proof` and know to be valid. - // New state is persisted after finalization. - self.finalize(finality_proof.clone())?; - metric_inc!(self.metrics, beefy_good_votes_processed); - return Ok(Some(finality_proof)); - }, - VoteImportResult::Ok => { - // Persist state after handling mandatory block vote. - if self - .voting_oracle() - .mandatory_pending() - .map(|(mandatory_num, _)| mandatory_num == block_number) - .unwrap_or(false) - { - crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) - .map_err(|e| Error::Backend(e.to_string()))?; - } - metric_inc!(self.metrics, beefy_good_votes_processed); - }, - VoteImportResult::Equivocation(proof) => { - metric_inc!(self.metrics, beefy_equivocation_votes); - self.report_equivocation(proof)?; - }, - VoteImportResult::Invalid => metric_inc!(self.metrics, beefy_invalid_votes), - VoteImportResult::Stale => metric_inc!(self.metrics, beefy_stale_votes), - }; - Ok(None) - } - - /// Provide BEEFY finality for block based on `finality_proof`: - /// 1. Prune now-irrelevant past sessions from the oracle, - /// 2. Set BEEFY best block, - /// 3. Persist voter state, - /// 4. Send best block hash and `finality_proof` to RPC worker. - /// - /// Expects `finality proof` to be valid and for a block > current-best-beefy. - fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { - let block_num = match finality_proof { - VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, - }; - - if block_num <= self.persisted_state.voting_oracle.best_beefy_block { - // we've already finalized this round before, short-circuit. - return Ok(()); - } - - // Finalize inner round and update voting_oracle state. - self.persisted_state.voting_oracle.finalize(block_num)?; - - // Set new best BEEFY block number. - self.persisted_state.set_best_beefy(block_num); - crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) - .map_err(|e| Error::Backend(e.to_string()))?; - - metric_set!(self.metrics, beefy_best_block, block_num); - - self.comms.on_demand_justifications.cancel_requests_older_than(block_num); - - if let Err(e) = self - .backend - .blockchain() - .expect_block_hash_from_id(&BlockId::Number(block_num)) - .and_then(|hash| { - self.links - .to_rpc_best_block_sender - .notify(|| Ok::<_, ()>(hash)) - .expect("forwards closure result; the closure always returns Ok; qed."); - - self.backend - .append_justification(hash, (BEEFY_ENGINE_ID, finality_proof.encode())) - }) { - debug!( - target: LOG_TARGET, - "🥩 Error {:?} on appending justification: {:?}", e, finality_proof - ); - } - - self.links - .to_rpc_justif_sender - .notify(|| Ok::<_, ()>(finality_proof.clone())) - .expect("forwards closure result; the closure always returns Ok; qed."); - - // Update gossip validator votes filter. - self.persisted_state - .gossip_filter_config() - .map(|filter| self.comms.gossip_validator.update_filter(filter))?; - - // finally update the latest signatures in storage - let best_header = self.persisted_state.voting_oracle.best_grandpa_block_header.clone(); - let best_hash = best_header.hash(); - - let signatures: Vec> = match finality_proof { - VersionedFinalityProof::V1(ref sc) => sc.signatures.clone(), - }; - - let signatures: Vec> = - signatures.iter().flatten().map(|sig| sig.encode()).collect::>(); - - info!( - target: LOG_TARGET, - "🥩 attempting to write signatures to the beacon pallet" - ); - - let rounds = self.persisted_state.voting_oracle.active_rounds()?; - let (validators, _validator_set_id) = (rounds.validators(), rounds.validator_set_id()); - // let offender_id = proof.offender_id().clone(); - // TODO: error handling - let _offender_id = self.key_store.authority_id(validators).unwrap(); - - let mut runtime_api = self.runtime.runtime_api(); - - // Register the offchain tx pool to be able to use it from the runtime. - runtime_api - .register_extension(self.offchain_tx_pool_factory.offchain_transaction_pool(best_hash)); - - let _ = runtime_api.submit_unsigned_pulse(best_hash, signatures, block_num); - - Ok(()) - } - - /// Handle previously buffered justifications, that now land in the voting interval. - fn try_pending_justifications(&mut self) -> Result<(), Error> { - // Interval of blocks for which we can process justifications and votes right now. - let (start, end) = self.voting_oracle().accepted_interval()?; - // Process pending justifications. - if !self.pending_justifications.is_empty() { - // These are still pending. - let still_pending = - self.pending_justifications.split_off(&end.saturating_add(1u32.into())); - // These can be processed. - let justifs_to_process = self.pending_justifications.split_off(&start); - // The rest can be dropped. - self.pending_justifications = still_pending; - - for (num, justification) in justifs_to_process.into_iter() { - debug!(target: LOG_TARGET, "🥩 Handle buffered justification for: {:?}.", num); - metric_inc!(self.metrics, beefy_imported_justifications); - if let Err(err) = self.finalize(justification) { - error!(target: LOG_TARGET, "🥩 Error finalizing block: {}", err); - } - } - metric_set!( - self.metrics, - beefy_buffered_justifications, - self.pending_justifications.len() - ); - } - Ok(()) - } - - /// Decide if should vote, then vote.. or don't.. - fn try_to_vote(&mut self) -> Result<(), Error> { - // Vote if there's now a new vote target. - if let Some(target) = self.voting_oracle().voting_target() { - metric_set!(self.metrics, beefy_should_vote_on, target); - if target > self.persisted_state.best_voted { - self.do_vote(target)?; - } - } - Ok(()) - } - - /// Create and gossip Signed Commitment for block number `target_number`. - /// - /// Also handle this self vote by calling `self.handle_vote()` for it. - fn do_vote(&mut self, target_number: NumberFor) -> Result<(), Error> { - debug!(target: LOG_TARGET, "🥩 Try voting on {}", target_number); - - // Most of the time we get here, `target` is actually `best_grandpa`, - // avoid getting header from backend in that case. - let target_header = if target_number == self.best_grandpa_block() { - self.persisted_state.voting_oracle.best_grandpa_block_header.clone() - } else { - let hash = self - .backend - .blockchain() - .expect_block_hash_from_id(&BlockId::Number(target_number)) - .map_err(|err| { - let err_msg = format!( - "Couldn't get hash for block #{:?} (error: {:?}), skipping vote..", - target_number, err - ); - Error::Backend(err_msg) - })?; - - self.backend.blockchain().expect_header(hash).map_err(|err| { - let err_msg = format!( - "Couldn't get header for block #{:?} ({:?}) (error: {:?}), skipping vote..", - target_number, hash, err - ); - Error::Backend(err_msg) - })? - }; - let target_hash = target_header.hash(); - - let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; - let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); - - let authority_id = if let Some(id) = self.key_store.authority_id(validators) { - debug!(target: LOG_TARGET, "🥩 Local authority id: {:?}", id); - id - } else { - debug!( - target: LOG_TARGET, - "🥩 Missing validator id - can't vote for: {:?}", target_hash - ); - return Ok(()); - }; - - if let Some((signature, _id, commitment)) = self - .get_signed_payload( - target_number, - target_header, - // target_hash, - validator_set_id, - authority_id.clone(), - ) - .map_err(|err| { - error!(target: LOG_TARGET, "🥩 Error calculating the signature {:?}", err); - // return Ok(()); - return err; - })? { - let vote = VoteMessage { commitment, id: authority_id, signature }; - if let Some(finality_proof) = self.handle_vote(vote.clone()).map_err(|err| { - error!(target: LOG_TARGET, "🥩 Error handling self vote: {}", err); - err - })? { - let encoded_proof = GossipMessage::::FinalityProof(finality_proof).encode(); - self.comms - .gossip_engine - .gossip_message(proofs_topic::(), encoded_proof, true); - } else { - metric_inc!(self.metrics, beefy_votes_sent); - debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", vote); - let encoded_vote = GossipMessage::::Vote(vote).encode(); - self.comms.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); - } - - // Persist state after vote to avoid double voting in case of voter restarts. - self.persisted_state.best_voted = target_number; - metric_set!(self.metrics, beefy_best_voted, target_number); - return crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) - .map_err(|e| Error::Backend(e.to_string())); - } - - Ok(()) - } - - #[cfg(feature = "bls-experimental")] - fn get_signed_payload( - &mut self, - target_number: NumberFor, - target_header: B::Header, - validator_set_id: ValidatorSetId, - authority_id: AuthorityId, - ) -> Result>)>, Error> { - let target_hash = target_header.hash(); - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let commitment = Commitment { payload, block_number: target_number, validator_set_id }; - let encoded_commitment = commitment.encode(); - - let (etf_authority_id, signature) = - match self.etf_extract(target_hash, authority_id.clone(), &encoded_commitment) { - Some(sig) => sig, - None => { - error!(target: LOG_TARGET, "🎲 Error calculating ETF signature"); - return Ok(None); - }, - }; - - info!( - target: LOG_TARGET, - "🎲 Produced signature using {:?}, is_valid: {:?}", - authority_id, - BeefyKeystore::verify(&etf_authority_id, &signature, &encoded_commitment) - ); - - Ok(Some((signature, etf_authority_id, commitment))) - } - - #[cfg(not(feature = "bls-experimental"))] - fn get_signed_payload( - &self, - target_number: NumberFor, - target_header: B::Header, - validator_set_id: ValidatorSetId, - authority_id: AuthorityId, - ) -> Result>)>, Error> { - let target_hash = target_header.hash(); - let payload = if let Some(hash) = self.payload_provider.payload(&target_header) { - hash - } else { - warn!(target: LOG_TARGET, "🥩 No MMR root digest found for: {:?}", target_hash); - return Ok(None); - }; - let commitment = Commitment { payload, block_number: target_number, validator_set_id }; - let encoded_commitment = commitment.encode(); - - let signature = match self.key_store.sign(&authority_id, &encoded_commitment) { - Ok(sig) => sig, - Err(err) => { - warn!(target: LOG_TARGET, "🥩 Error signing commitment: {:?}", err); - return Ok(None); - }, - }; - - info!( - target: LOG_TARGET, - "🥩 Produced signature using {:?}, is_valid: {:?}", - authority_id, - BeefyKeystore::verify(&authority_id, &signature, &encoded_commitment) - ); - - Ok(Some((signature, authority_id, commitment))) - } - - fn process_new_state(&mut self) { - // Handle pending justifications and/or votes for now GRANDPA finalized blocks. - if let Err(err) = self.try_pending_justifications() { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - // Don't bother voting or requesting justifications during major sync. - if !self.sync.is_major_syncing() { - // There were external events, 'state' is changed, author a vote if needed/possible. - if let Err(err) = self.try_to_vote() { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - // If the current target is a mandatory block, - // make sure there's also an on-demand justification request out for it. - if let Some((block, active)) = self.voting_oracle().mandatory_pending() { - // This only starts new request if there isn't already an active one. - self.comms.on_demand_justifications.request(block, active); - } - } - } - - /// execute the ETF extract algorithm - /// outputs a (threshold) IBE secret and corresponding DLEQ proof - #[cfg(feature = "bls-experimental")] - fn etf_extract( - &mut self, - hash: B::Hash, - id: AuthorityId, - message: &[u8], - ) -> Option<(AuthorityId, Signature)> { - let runtime_api = self.runtime.runtime_api(); - - info!( - target: LOG_TARGET, - "🎲 run ACSS recovery at best grandpa: #{:?}.", - hash - ); - if let Some(Some(validator_set)) = runtime_api.validator_set(hash).ok() { - debug!(target: LOG_TARGET, "🎲 [ETF] validator_set: {:?}", validator_set); - if let Some(Some(pok_bytes)) = runtime_api.read_share(hash, id.clone()).ok() { - debug!(target: LOG_TARGET, "🎲 [ETF] pok_bytes: {:?}", pok_bytes); - match self.key_store.etf_sign(&id, &pok_bytes, &message, validator_set.len() as u8) - { - Ok((pk, sig)) => return Some((pk, sig)), - Err(e) => error!(target: LOG_TARGET, "🎲 [ETF] Error signing: {:?}", e), - } - } - } - debug!( - target: LOG_TARGET, - "🎲 [ETF] extract failed with id: {:?} and message: {:?}", - id, - message); - None - } - - /// Main loop for BEEFY worker. - /// - /// Run the main async loop which is driven by finality notifications and gossiped votes. - /// Should never end, returns `Error` otherwise. - pub(crate) async fn run( - mut self, - block_import_justif: &mut Fuse>>, - finality_notifications: &mut Fuse>, - ) -> (Error, BeefyComms) { - info!( - target: LOG_TARGET, - "🥩 run BEEFY worker, best grandpa: #{:?}.", - self.best_grandpa_block() - ); - - let mut votes = Box::pin( - self.comms - .gossip_engine - .messages_for(votes_topic::()) - .filter_map(|notification| async move { - let vote = GossipMessage::::decode_all(&mut ¬ification.message[..]) - .ok() - .and_then(|message| message.unwrap_vote()); - trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", vote); - vote - }) - .fuse(), - ); - let mut gossip_proofs = Box::pin( - self.comms - .gossip_engine - .messages_for(proofs_topic::()) - .filter_map(|notification| async move { - let proof = GossipMessage::::decode_all(&mut ¬ification.message[..]) - .ok() - .and_then(|message| message.unwrap_finality_proof()); - trace!(target: LOG_TARGET, "🥩 Got gossip proof message: {:?}", proof); - proof - }) - .fuse(), - ); - - self.process_new_state(); - let error = loop { - // Mutable reference used to drive the gossip engine. - let mut gossip_engine = &mut self.comms.gossip_engine; - - // Wait for, and handle external events. - // The branches below only change 'state', actual voting happens afterwards, - // based on the new resulting 'state'. - futures::select_biased! { - // Use `select_biased!` to prioritize order below. - // Process finality notifications first since these drive the voter. - notification = finality_notifications.next() => { - if let Some(notif) = notification { - - if let Err(err) = self.handle_finality_notification(¬if) { - break err; - } - } else { - break Error::FinalityStreamTerminated; - } - }, - // Make sure to pump gossip engine. - _ = gossip_engine => { - break Error::GossipEngineTerminated; - }, - // Process incoming justifications as these can make some in-flight votes obsolete. - response_info = self.comms.on_demand_justifications.next().fuse() => { - match response_info { - ResponseInfo::ValidProof(justif, peer_report) => { - if let Err(err) = self.triage_incoming_justif(justif) { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - self.comms.gossip_engine.report(peer_report.who, peer_report.cost_benefit); - }, - ResponseInfo::PeerReport(peer_report) => { - self.comms.gossip_engine.report(peer_report.who, peer_report.cost_benefit); - continue; - }, - ResponseInfo::Pending => { - continue; - }, - } - }, - justif = block_import_justif.next() => { - if let Some(justif) = justif { - // Block import justifications have already been verified to be valid - // by `BeefyBlockImport`. - if let Err(err) = self.triage_incoming_justif(justif) { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - } else { - break Error::BlockImportStreamTerminated; - } - }, - justif = gossip_proofs.next() => { - if let Some(justif) = justif { - // Gossiped justifications have already been verified by `GossipValidator`. - if let Err(err) = self.triage_incoming_justif(justif) { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - } else { - break Error::FinalityProofGossipStreamTerminated; - } - }, - // Finally process incoming votes. - vote = votes.next() => { - if let Some(vote) = vote { - // Votes have already been verified to be valid by the gossip validator. - if let Err(err) = self.triage_incoming_vote(vote) { - debug!(target: LOG_TARGET, "🥩 {}", err); - } - } else { - break Error::VotesGossipStreamTerminated; - } - }, - // Process peer reports. - report = self.comms.gossip_report_stream.next() => { - if let Some(PeerReport { who, cost_benefit }) = report { - self.comms.gossip_engine.report(who, cost_benefit); - } - continue; - }, - } - - // Act on changed 'state'. - self.process_new_state(); - }; - - // return error _and_ `comms` that can be reused - (error, self.comms) - } - - /// Report the given equivocation to the BEEFY runtime module. This method - /// generates a session membership proof of the offender and then submits an - /// extrinsic to report the equivocation. In particular, the session membership - /// proof must be generated at the block at which the given set was active which - /// isn't necessarily the best block if there are pending authority set changes. - pub(crate) fn report_equivocation( - &self, - proof: EquivocationProof, AuthorityId, Signature>, - ) -> Result<(), Error> { - let rounds = self.persisted_state.voting_oracle.active_rounds()?; - let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); - let offender_id = proof.offender_id().clone(); - - if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) { - debug!(target: LOG_TARGET, "🥩 Skip report for bad equivocation {:?}", proof); - return Ok(()); - } else if let Some(local_id) = self.key_store.authority_id(validators) { - if offender_id == local_id { - warn!(target: LOG_TARGET, "🥩 Skip equivocation report for own equivocation"); - return Ok(()); - } - } - - let number = *proof.round_number(); - let hash = self - .backend - .blockchain() - .expect_block_hash_from_id(&BlockId::Number(number)) - .map_err(|err| { - let err_msg = format!( - "Couldn't get hash for block #{:?} (error: {:?}), skipping report for equivocation", - number, err - ); - Error::Backend(err_msg) - })?; - let runtime_api = self.runtime.runtime_api(); - // generate key ownership proof at that block - let key_owner_proof = match runtime_api - .generate_key_ownership_proof(hash, validator_set_id, offender_id) - .map_err(Error::RuntimeApi)? - { - Some(proof) => proof, - None => { - debug!( - target: LOG_TARGET, - "🥩 Equivocation offender not part of the authority set." - ); - return Ok(()); - }, - }; - - // submit equivocation report at **best** block - let best_block_hash = self.backend.blockchain().info().best_hash; - runtime_api - .submit_report_equivocation_unsigned_extrinsic(best_block_hash, proof, key_owner_proof) - .map_err(Error::RuntimeApi)?; - - Ok(()) - } -} - -/// Calculate next block number to vote on. -/// -/// Return `None` if there is no votable target yet. -// TODO: this function is not used, remove it? -// https://github.com/ideal-lab5/idn-sdk/issues/63 -#[allow(dead_code)] -fn vote_target(best_grandpa: N, best_beefy: N, session_start: N, min_delta: u32) -> Option -where - N: AtLeast32Bit + Copy + Debug, -{ - // if the mandatory block (session_start) does not have a beefy justification yet, - // we vote on it - let target = if best_beefy < session_start { - debug!(target: LOG_TARGET, "🥩 vote target - mandatory block: #{:?}", session_start); - session_start - } else { - let diff = best_grandpa.saturating_sub(best_beefy) + 1u32.into(); - let diff = diff.saturated_into::() / 2; - let target = best_beefy + min_delta.max(diff.next_power_of_two()).into(); - trace!( - target: LOG_TARGET, - "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", - diff, - diff.next_power_of_two(), - target, - ); - - target - }; - - // Don't vote for targets until they've been finalized - // (`target` can be > `best_grandpa` when `min_delta` is big enough). - if target > best_grandpa { - None - } else { - Some(target) - } -} - -/// Verify `active` validator set for `block` against the key store -/// -/// We want to make sure that we have _at least one_ key in our keystore that -/// is part of the validator set, that's because if there are no local keys -/// then we can't perform our job as a validator. -/// -/// Note that for a non-authority node there will be no keystore, and we will -/// return an error and don't check. The error can usually be ignored. -fn verify_validator_set( - block: &NumberFor, - active: &ValidatorSet, - key_store: &BeefyKeystore, -) -> Result<(), Error> { - let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); - - let public_keys = 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(()) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::{ - communication::{ - gossip::GossipValidator, - notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, - request_response::outgoing_requests_engine::OnDemandJustificationsEngine, - }, - tests::{ - create_beefy_keystore, get_beefy_streams, make_beefy_ids, BeefyPeer, BeefyTestNet, - TestApi, - }, - BeefyRPCLinks, KnownPeers, - }; - use futures::{future::poll_fn, task::Poll}; - use parking_lot::Mutex; - use sc_client_api::{Backend as BackendT, HeaderBackend}; - use sc_network_gossip::GossipEngine; - use sc_network_sync::SyncingService; - use sc_network_test::TestNetFactory; - use sp_blockchain::Backend as BlockchainBackendT; - use sp_consensus_beefy_etf::{ - known_payloads, - known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, - test_utils::{generate_equivocation_proof, Keyring}, - ConsensusLog, Payload, SignedCommitment, - }; - use sp_runtime::traits::{Header as HeaderT, One}; - use substrate_test_runtime_client::{ - runtime::{Block, Digest, DigestItem, Header}, - Backend, - }; - - impl PersistedState { - pub fn active_round(&self) -> Result<&Rounds, Error> { - self.voting_oracle.active_rounds() - } - - pub fn best_grandpa_number(&self) -> NumberFor { - *self.voting_oracle.best_grandpa_block_header.number() - } - } - - impl VoterOracle { - pub fn sessions(&self) -> &VecDeque> { - &self.sessions - } - } - - fn create_beefy_worker( - peer: &mut BeefyPeer, - key: &Keyring, - min_block_delta: u32, - genesis_validator_set: ValidatorSet, - ) -> BeefyWorker< - Block, - Backend, - MmrRootProvider, - TestApi, - Arc>, - > { - let keystore = create_beefy_keystore(key); - - let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); - let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = - BeefyBestBlockStream::::channel(); - let (_, from_block_import_justif_stream) = - 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); - - let links = BeefyVoterLinks { - from_block_import_justif_stream, - to_rpc_justif_sender, - to_rpc_best_block_sender, - }; - - let backend = peer.client().as_backend(); - let beefy_genesis = 1; - let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); - let network = peer.network_service().clone(); - let sync = peer.sync_service().clone(); - let notification_service = peer - .take_notification_service(&crate::tests::beefy_gossip_proto_name()) - .unwrap(); - let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let (gossip_validator, gossip_report_stream) = GossipValidator::new(known_peers.clone()); - let gossip_validator = Arc::new(gossip_validator); - let gossip_engine = GossipEngine::new( - network.clone(), - sync.clone(), - notification_service, - "/beefy/1", - gossip_validator.clone(), - None, - ); - let metrics = None; - let on_demand_justifications = OnDemandJustificationsEngine::new( - network.clone(), - "/beefy/justifs/1".into(), - known_peers, - None, - ); - // Push 1 block - will start first session. - let hashes = peer.push_blocks(1, false); - backend.finalize_block(hashes[0], None).unwrap(); - let first_header = backend - .blockchain() - .expect_header(backend.blockchain().info().best_hash) - .unwrap(); - let persisted_state = PersistedState::checked_new( - first_header, - Zero::zero(), - vec![Rounds::new(One::one(), genesis_validator_set)].into(), - min_block_delta, - beefy_genesis, - ) - .unwrap(); - let payload_provider = MmrRootProvider::new(api.clone()); - let comms = BeefyComms { - gossip_engine, - gossip_validator, - gossip_report_stream, - on_demand_justifications, - }; - BeefyWorker { - backend, - runtime: api, - key_store: Some(keystore).into(), - metrics, - payload_provider, - sync: Arc::new(sync), - links, - comms, - pending_justifications: BTreeMap::new(), - persisted_state, - } - } - - #[test] - fn vote_on_min_block_delta() { - let t = vote_target(1u32, 1, 1, 4); - assert_eq!(None, t); - let t = vote_target(2u32, 1, 1, 4); - assert_eq!(None, t); - let t = vote_target(4u32, 2, 1, 4); - assert_eq!(None, t); - let t = vote_target(6u32, 2, 1, 4); - assert_eq!(Some(6), t); - - let t = vote_target(9u32, 4, 1, 4); - assert_eq!(Some(8), t); - - let t = vote_target(10u32, 10, 1, 8); - assert_eq!(None, t); - let t = vote_target(12u32, 10, 1, 8); - assert_eq!(None, t); - let t = vote_target(18u32, 10, 1, 8); - assert_eq!(Some(18), t); - } - - #[test] - fn vote_on_power_of_two() { - let t = vote_target(1008u32, 1000, 1, 4); - assert_eq!(Some(1004), t); - - let t = vote_target(1016u32, 1000, 1, 4); - assert_eq!(Some(1008), t); - - let t = vote_target(1032u32, 1000, 1, 4); - assert_eq!(Some(1016), t); - - let t = vote_target(1064u32, 1000, 1, 4); - assert_eq!(Some(1032), t); - - let t = vote_target(1128u32, 1000, 1, 4); - assert_eq!(Some(1064), t); - - let t = vote_target(1256u32, 1000, 1, 4); - assert_eq!(Some(1128), t); - - let t = vote_target(1512u32, 1000, 1, 4); - assert_eq!(Some(1256), t); - - let t = vote_target(1024u32, 1, 1, 4); - assert_eq!(Some(513), t); - } - - #[test] - fn vote_on_target_block() { - let t = vote_target(1008u32, 1002, 1, 4); - assert_eq!(Some(1006), t); - let t = vote_target(1010u32, 1002, 1, 4); - assert_eq!(Some(1006), t); - - let t = vote_target(1016u32, 1006, 1, 4); - assert_eq!(Some(1014), t); - let t = vote_target(1022u32, 1006, 1, 4); - assert_eq!(Some(1014), t); - - let t = vote_target(1032u32, 1012, 1, 4); - assert_eq!(Some(1028), t); - let t = vote_target(1044u32, 1012, 1, 4); - assert_eq!(Some(1028), t); - - let t = vote_target(1064u32, 1014, 1, 4); - assert_eq!(Some(1046), t); - let t = vote_target(1078u32, 1014, 1, 4); - assert_eq!(Some(1046), t); - - let t = vote_target(1128u32, 1008, 1, 4); - assert_eq!(Some(1072), t); - let t = vote_target(1136u32, 1008, 1, 4); - assert_eq!(Some(1072), t); - } - - #[test] - fn vote_on_mandatory_block() { - let t = vote_target(1008u32, 1002, 1004, 4); - assert_eq!(Some(1004), t); - let t = vote_target(1016u32, 1006, 1007, 4); - assert_eq!(Some(1007), t); - let t = vote_target(1064u32, 1014, 1063, 4); - assert_eq!(Some(1063), t); - let t = vote_target(1320u32, 1012, 1234, 4); - assert_eq!(Some(1234), t); - - let t = vote_target(1128u32, 1008, 1008, 4); - assert_eq!(Some(1072), t); - } - - #[test] - fn should_vote_target() { - let header = Header::new( - 1u32.into(), - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - let mut oracle = VoterOracle:: { - best_beefy_block: 0, - best_grandpa_block_header: header, - min_block_delta: 1, - sessions: VecDeque::new(), - }; - let voting_target_with = |oracle: &mut VoterOracle, - best_beefy: NumberFor, - best_grandpa: NumberFor| - -> Option> { - oracle.best_beefy_block = best_beefy; - oracle.best_grandpa_block_header.number = best_grandpa; - oracle.voting_target() - }; - - // rounds not initialized -> should vote: `None` - assert_eq!(voting_target_with(&mut oracle, 0, 1), None); - - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - - oracle.add_session(Rounds::new(1, validator_set.clone())); - - // under min delta - oracle.min_block_delta = 4; - assert_eq!(voting_target_with(&mut oracle, 1, 1), None); - assert_eq!(voting_target_with(&mut oracle, 2, 5), None); - - // vote on min delta - assert_eq!(voting_target_with(&mut oracle, 4, 9), Some(8)); - oracle.min_block_delta = 8; - assert_eq!(voting_target_with(&mut oracle, 10, 18), Some(18)); - - // vote on power of two - oracle.min_block_delta = 1; - assert_eq!(voting_target_with(&mut oracle, 1000, 1008), Some(1004)); - assert_eq!(voting_target_with(&mut oracle, 1000, 1016), Some(1008)); - - // nothing new to vote on - assert_eq!(voting_target_with(&mut oracle, 1000, 1000), None); - - // vote on mandatory - oracle.sessions.clear(); - oracle.add_session(Rounds::new(1000, validator_set.clone())); - assert_eq!(voting_target_with(&mut oracle, 0, 1008), Some(1000)); - oracle.sessions.clear(); - oracle.add_session(Rounds::new(1001, validator_set.clone())); - assert_eq!(voting_target_with(&mut oracle, 1000, 1008), Some(1001)); - } - - #[test] - fn test_oracle_accepted_interval() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - - let header = Header::new( - 1u32.into(), - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - let mut oracle = VoterOracle:: { - best_beefy_block: 0, - best_grandpa_block_header: header, - min_block_delta: 1, - sessions: VecDeque::new(), - }; - let accepted_interval_with = |oracle: &mut VoterOracle, - best_grandpa: NumberFor| - -> Result<(NumberFor, NumberFor), Error> { - oracle.best_grandpa_block_header.number = best_grandpa; - oracle.accepted_interval() - }; - - // rounds not initialized -> should accept votes: `None` - assert!(accepted_interval_with(&mut oracle, 1).is_err()); - - let session_one = 1; - oracle.add_session(Rounds::new(session_one, validator_set.clone())); - // mandatory not done, only accept mandatory - for i in 0..15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_one, session_one))); - } - - // add more sessions, nothing changes - let session_two = 11; - let session_three = 21; - oracle.add_session(Rounds::new(session_two, validator_set.clone())); - oracle.add_session(Rounds::new(session_three, validator_set.clone())); - // mandatory not done, should accept mandatory for session_one - for i in session_three..session_three + 15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_one, session_one))); - } - - // simulate finish mandatory for session one, prune oracle - oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); - oracle.try_prune(); - // session_one pruned, should accept mandatory for session_two - for i in session_three..session_three + 15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_two, session_two))); - } - - // simulate finish mandatory for session two, prune oracle - oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); - oracle.try_prune(); - // session_two pruned, should accept mandatory for session_three - for i in session_three..session_three + 15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_three, session_three))); - } - - // simulate finish mandatory for session three - oracle.sessions.front_mut().unwrap().test_set_mandatory_done(true); - // verify all other blocks in this session are now open to voting - for i in session_three..session_three + 15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_three, i))); - } - // pruning does nothing in this case - oracle.try_prune(); - for i in session_three..session_three + 15 { - assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_three, i))); - } - - // adding new session automatically prunes "finalized" previous session - let session_four = 31; - oracle.add_session(Rounds::new(session_four, validator_set.clone())); - assert_eq!(oracle.sessions.front().unwrap().session_start(), session_four); - assert_eq!( - accepted_interval_with(&mut oracle, session_four + 10), - Ok((session_four, session_four)) - ); - } - - #[test] - fn extract_authorities_change_digest() { - let mut header = Header::new( - 1u32.into(), - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - - // verify empty digest shows nothing - 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(); - header.digest_mut().push(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::AuthoritiesChange(validator_set.clone()).encode(), - )); - - // verify validator set is correctly extracted from digest - let extracted = find_authorities_change::(&header); - assert_eq!(extracted, Some(validator_set)); - } - - #[tokio::test] - async fn keystore_vs_validator_set() { - let keys = &[Keyring::Alice]; - 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()); - - // keystore doesn't contain other keys than validators' - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), Ok(())); - - // unknown `Bob` key - let keys = &[Keyring::Bob]; - 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!(verify_validator_set::(&1, &validator_set, &worker.key_store), expected); - - // worker has no keystore - worker.key_store = None.into(); - let expected_err = Err(Error::Keystore("no Keystore".into())); - assert_eq!( - verify_validator_set::(&1, &validator_set, &worker.key_store), - expected_err - ); - } - - #[tokio::test] - async fn should_finalize_correctly() { - let keys = [Keyring::Alice]; - 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()); - // remove default session, will manually add custom one. - worker.persisted_state.voting_oracle.sessions.clear(); - - let keys = keys.iter().cloned().enumerate(); - let (mut best_block_streams, mut finality_proofs) = - get_beefy_streams(&mut net, keys.clone()); - let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - let mut finality_proof = finality_proofs.drain(..).next().unwrap(); - - let create_finality_proof = |block_num: NumberFor| { - let commitment = Commitment { - payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), - block_number: block_num, - validator_set_id: validator_set.id(), - }; - VersionedFinalityProof::V1(SignedCommitment { commitment, signatures: vec![None] }) - }; - - // no 'best beefy block' or finality proofs - assert_eq!(worker.persisted_state.best_beefy(), 0); - poll_fn(move |cx| { - assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); - assert_eq!(finality_proof.poll_next_unpin(cx), Poll::Pending); - Poll::Ready(()) - }) - .await; - - let client = net.peer(0).client().as_client(); - // unknown hash for block #1 - let (mut best_block_streams, mut finality_proofs) = - get_beefy_streams(&mut net, keys.clone()); - let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - let mut finality_proof = finality_proofs.drain(..).next().unwrap(); - let justif = create_finality_proof(1); - // create new session at block #1 - worker - .persisted_state - .voting_oracle - .add_session(Rounds::new(1, validator_set.clone())); - // try to finalize block #1 - worker.finalize(justif.clone()).unwrap(); - // verify block finalized - assert_eq!(worker.persisted_state.best_beefy(), 1); - poll_fn(move |cx| { - // expect Some(hash-of-block-1) - match best_block_stream.poll_next_unpin(cx) { - Poll::Ready(Some(hash)) => { - let block_num = client.number(hash).unwrap(); - assert_eq!(block_num, Some(1)); - }, - v => panic!("unexpected value: {:?}", v), - } - // commitment streamed - match finality_proof.poll_next_unpin(cx) { - // expect justification - Poll::Ready(Some(received)) => assert_eq!(received, justif), - v => panic!("unexpected value: {:?}", v), - } - Poll::Ready(()) - }) - .await; - - // generate 2 blocks, try again expect success - let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); - let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); - let hashes = net.peer(0).push_blocks(1, false); - // finalize 1 and 2 without justifications (hashes does not contain genesis) - let hashof2 = hashes[0]; - backend.finalize_block(hashof2, None).unwrap(); - - let justif = create_finality_proof(2); - // create new session at block #2 - worker.persisted_state.voting_oracle.add_session(Rounds::new(2, validator_set)); - worker.finalize(justif).unwrap(); - // verify old session pruned - assert_eq!(worker.voting_oracle().sessions.len(), 1); - // new session starting at #2 is in front - assert_eq!(worker.active_rounds().unwrap().session_start(), 2); - // verify block finalized - assert_eq!(worker.persisted_state.best_beefy(), 2); - poll_fn(move |cx| { - match best_block_stream.poll_next_unpin(cx) { - // expect Some(hash-of-block-2) - Poll::Ready(Some(hash)) => { - let block_num = net.peer(0).client().as_client().number(hash).unwrap(); - assert_eq!(block_num, Some(2)); - }, - v => panic!("unexpected value: {:?}", v), - } - Poll::Ready(()) - }) - .await; - - // check BEEFY justifications are also appended to backend - let justifs = backend.blockchain().justifications(hashof2).unwrap().unwrap(); - assert!(justifs.get(BEEFY_ENGINE_ID).is_some()) - } - - #[tokio::test] - async fn should_init_session() { - 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 worker_rounds = worker.active_rounds().unwrap(); - assert_eq!(worker_rounds.session_start(), 1); - assert_eq!(worker_rounds.validators(), validator_set.validators()); - assert_eq!(worker_rounds.validator_set_id(), validator_set.id()); - - // new validator set - let keys = &[Keyring::Bob]; - 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. - let rounds = worker.persisted_state.voting_oracle.active_rounds_mut().unwrap(); - assert_eq!(rounds.validator_set_id(), validator_set.id()); - // Let's finalize mandatory. - rounds.test_set_mandatory_done(true); - worker.persisted_state.voting_oracle.try_prune(); - // Now we should get the next round. - let rounds = worker.active_rounds().unwrap(); - // Expect new values. - assert_eq!(rounds.session_start(), 11); - assert_eq!(rounds.validators(), new_validator_set.validators()); - assert_eq!(rounds.validator_set_id(), new_validator_set.id()); - } - - #[tokio::test] - async fn should_not_report_bad_old_or_self_equivocations() { - let block_num = 1; - let set_id = 1; - let keys = [Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(&keys), set_id).unwrap(); - // Alice votes on good MMR roots, equivocations are allowed/expected - let mut api_alice = TestApi::with_validator_set(&validator_set); - api_alice.allow_equivocations(); - let api_alice = Arc::new(api_alice); - - let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); - worker.runtime = api_alice.clone(); - - // let there be a block with num = 1: - let _ = net.peer(0).push_blocks(1, false); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - - // generate an equivocation proof, with Bob as perpetrator - let good_proof = generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &Keyring::Bob), - (block_num, payload2.clone(), set_id, &Keyring::Bob), - ); - { - // expect voter (Alice) to successfully report it - assert_eq!(worker.report_equivocation(good_proof.clone()), Ok(())); - // verify Alice reports Bob equivocation to runtime - let reported = api_alice.reported_equivocations.as_ref().unwrap().lock(); - assert_eq!(reported.len(), 1); - assert_eq!(*reported.get(0).unwrap(), good_proof); - } - api_alice.reported_equivocations.as_ref().unwrap().lock().clear(); - - // now let's try with a bad proof - let mut bad_proof = good_proof.clone(); - bad_proof.first.id = Keyring::Charlie.public(); - // bad proofs are simply ignored - assert_eq!(worker.report_equivocation(bad_proof), Ok(())); - // verify nothing reported to runtime - assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); - - // now let's try with old set it - let mut old_proof = good_proof.clone(); - old_proof.first.commitment.validator_set_id = 0; - old_proof.second.commitment.validator_set_id = 0; - // old proofs are simply ignored - assert_eq!(worker.report_equivocation(old_proof), Ok(())); - // verify nothing reported to runtime - assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); - - // now let's try reporting a self-equivocation - let self_proof = generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &Keyring::Alice), - (block_num, payload2.clone(), set_id, &Keyring::Alice), - ); - // equivocations done by 'self' are simply ignored (not reported) - assert_eq!(worker.report_equivocation(self_proof), Ok(())); - // verify nothing reported to runtime - assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); - } -} From e337a4bbd1b19c6a8c58702e73fba8c241e0f58c Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 10:41:02 -0600 Subject: [PATCH 3/7] remove pallet/murmur, pallet/proxy, pallet/scheduler, pallet/beefy-etf, and pallet/beefy-mmr-etf --- Cargo.lock | 594 +----- Cargo.toml | 5 - pallets/beefy-etf/Cargo.toml | 87 - pallets/beefy-etf/src/default_weights.rs | 56 - pallets/beefy-etf/src/equivocation.rs | 287 --- pallets/beefy-etf/src/lib.rs | 555 ------ pallets/beefy-etf/src/mock.rs | 359 ---- pallets/beefy-etf/src/tests.rs | 864 --------- pallets/beefy-mmr-etf/Cargo.toml | 69 - pallets/beefy-mmr-etf/src/lib.rs | 255 --- pallets/beefy-mmr-etf/src/mock.rs | 202 -- pallets/beefy-mmr-etf/src/tests.rs | 239 --- pallets/etf/Cargo.toml | 2 - pallets/murmur/Cargo.toml | 108 -- pallets/murmur/README.md | 90 - pallets/murmur/src/lib.rs | 304 ---- pallets/murmur/src/mock.rs | 207 --- pallets/murmur/src/tests.rs | 310 ---- pallets/proxy/Cargo.toml | 59 - pallets/proxy/README.md | 63 - pallets/proxy/src/benchmarking.rs | 265 --- pallets/proxy/src/lib.rs | 815 --------- pallets/proxy/src/tests.rs | 597 ------ pallets/proxy/src/weights.rs | 399 ---- pallets/randomness-beacon/Cargo.toml | 3 - pallets/scheduler/Cargo.toml | 75 - pallets/scheduler/README.md | 34 - pallets/scheduler/src/benchmarking.rs | 361 ---- pallets/scheduler/src/lib.rs | 1192 ------------ pallets/scheduler/src/mock.rs | 343 ---- pallets/scheduler/src/tests.rs | 2123 ---------------------- pallets/scheduler/src/weights.rs | 226 --- 32 files changed, 21 insertions(+), 11127 deletions(-) delete mode 100644 pallets/beefy-etf/Cargo.toml delete mode 100644 pallets/beefy-etf/src/default_weights.rs delete mode 100644 pallets/beefy-etf/src/equivocation.rs delete mode 100644 pallets/beefy-etf/src/lib.rs delete mode 100644 pallets/beefy-etf/src/mock.rs delete mode 100644 pallets/beefy-etf/src/tests.rs delete mode 100644 pallets/beefy-mmr-etf/Cargo.toml delete mode 100644 pallets/beefy-mmr-etf/src/lib.rs delete mode 100644 pallets/beefy-mmr-etf/src/mock.rs delete mode 100644 pallets/beefy-mmr-etf/src/tests.rs delete mode 100644 pallets/murmur/Cargo.toml delete mode 100644 pallets/murmur/README.md delete mode 100644 pallets/murmur/src/lib.rs delete mode 100644 pallets/murmur/src/mock.rs delete mode 100644 pallets/murmur/src/tests.rs delete mode 100644 pallets/proxy/Cargo.toml delete mode 100644 pallets/proxy/README.md delete mode 100644 pallets/proxy/src/benchmarking.rs delete mode 100644 pallets/proxy/src/lib.rs delete mode 100644 pallets/proxy/src/tests.rs delete mode 100644 pallets/proxy/src/weights.rs delete mode 100644 pallets/scheduler/Cargo.toml delete mode 100644 pallets/scheduler/README.md delete mode 100644 pallets/scheduler/src/benchmarking.rs delete mode 100644 pallets/scheduler/src/lib.rs delete mode 100644 pallets/scheduler/src/mock.rs delete mode 100644 pallets/scheduler/src/tests.rs delete mode 100644 pallets/scheduler/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index b232e56..bf46af2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -297,7 +297,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.1", + "rustc_version", "zeroize", ] @@ -422,21 +422,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ark-secret-scalar" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf.git#0fef8266d851932ad25d6b41bc4b34d834d1e11d" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "digest 0.10.7", - "getrandom_or_panic", - "zeroize", -] - [[package]] name = "ark-serialize" version = "0.4.2" @@ -510,25 +495,6 @@ dependencies = [ "sha3", ] -[[package]] -name = "ark-transcript" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf.git#0fef8266d851932ad25d6b41bc4b34d834d1e11d" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "digest 0.10.7", - "rand_core 0.6.4", - "sha3", -] - -[[package]] -name = "array-bytes" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" - [[package]] name = "array-bytes" version = "6.2.3" @@ -887,7 +853,7 @@ dependencies = [ "ark-ff", "ark-serialize", "ark-std", - "dleq_vrf 0.0.2 (git+https://github.com/w3f/ring-vrf?rev=e9782f9)", + "dleq_vrf", "fflonk", "merlin", "rand_chacha 0.3.1", @@ -911,12 +877,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base32" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" - [[package]] name = "base64" version = "0.13.1" @@ -941,17 +901,6 @@ version = "13.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "hash-db", - "log", -] - -[[package]] -name = "binary-merkle-tree" -version = "15.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336bf780dd7526a9a4bc1521720b25c1994dc132cccd59553431923fa4d1a693" -dependencies = [ - "hash-db", - "log", ] [[package]] @@ -1011,7 +960,7 @@ checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq 0.3.1", + "constant_time_eq", ] [[package]] @@ -1161,15 +1110,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ckb-merkle-mountain-range" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" -dependencies = [ - "cfg-if", -] - [[package]] name = "common" version = "0.1.0" @@ -1226,12 +1166,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "constant_time_eq" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1371,7 +1305,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.1", + "rustc_version", "subtle", "zeroize", ] @@ -1488,12 +1422,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.9.0" @@ -1526,12 +1454,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "dissimilar" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" - [[package]] name = "dleq_vrf" version = "0.0.2" @@ -1540,7 +1462,7 @@ dependencies = [ "ark-ec", "ark-ff", "ark-scale 0.0.12", - "ark-secret-scalar 0.0.2 (git+https://github.com/w3f/ring-vrf?rev=e9782f9)", + "ark-secret-scalar", "ark-serialize", "ark-std", "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf?rev=e9782f9)", @@ -1548,21 +1470,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "dleq_vrf" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf.git#0fef8266d851932ad25d6b41bc4b34d834d1e11d" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-secret-scalar 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "arrayvec", - "zeroize", -] - [[package]] name = "docify" version = "0.2.9" @@ -1716,19 +1623,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "environmental" version = "1.1.4" @@ -1764,7 +1658,7 @@ dependencies = [ "ark-poly", "ark-serialize", "ark-std", - "array-bytes 6.2.3", + "array-bytes", "chacha20poly1305", "generic-array", "parity-scale-codec", @@ -1791,7 +1685,7 @@ dependencies = [ "ark-poly", "ark-serialize", "ark-std", - "array-bytes 6.2.3", + "array-bytes", "chacha20poly1305", "generic-array", "parity-scale-codec", @@ -2018,24 +1912,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "frame-executive" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "aquamarine", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "frame-metadata" version = "16.0.0" @@ -2054,7 +1930,7 @@ version = "28.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "aquamarine", - "array-bytes 6.2.3", + "array-bytes", "bitflags 1.3.2", "docify", "environmental", @@ -2096,7 +1972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7dd8b9f161a8289e3b9fe6c1068519358dbff2270d38097a923d3d1b4459dca" dependencies = [ "aquamarine", - "array-bytes 6.2.3", + "array-bytes", "bitflags 1.3.2", "docify", "environmental", @@ -2216,47 +2092,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "frame-support-test" -version = "3.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-executive", - "frame-metadata", - "frame-support 28.0.0", - "frame-support-test-pallet", - "frame-system 28.0.0", - "parity-scale-codec", - "pretty_assertions", - "rustversion", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-arithmetic 23.0.0", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-metadata-ir 0.6.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-version 29.0.0", - "static_assertions", - "trybuild", -] - -[[package]] -name = "frame-support-test-pallet" -version = "4.0.0-dev" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-system 28.0.0", - "parity-scale-codec", - "scale-info", - "serde", - "sp-runtime 31.0.1", -] - [[package]] name = "frame-system" version = "28.0.0" @@ -2523,12 +2358,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -2824,12 +2653,6 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "1.6.0" @@ -3206,17 +3029,6 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" -[[package]] -name = "is-terminal" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "itertools" version = "0.10.5" @@ -3916,7 +3728,7 @@ dependencies = [ "loom", "parking_lot", "portable-atomic", - "rustc_version 0.4.1", + "rustc_version", "smallvec", "tagptr", "thiserror 1.0.69", @@ -3983,42 +3795,6 @@ dependencies = [ "unsigned-varint 0.7.2", ] -[[package]] -name = "murmur-core" -version = "0.1.0" -source = "git+https://github.com/ideal-lab5/murmur.git#ab462716c77e18f7782147bafd4f9f5085159313" -dependencies = [ - "ark-bls12-377", - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "ckb-merkle-mountain-range", - "dleq_vrf 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "parity-scale-codec", - "serde", - "sha3", - "timelock 0.0.1 (git+https://github.com/ideal-lab5/timelock.git)", - "totp-rs", - "w3f-bls", - "zeroize", -] - -[[package]] -name = "murmur-test-utils" -version = "0.1.0" -source = "git+https://github.com/ideal-lab5/murmur.git#ab462716c77e18f7782147bafd4f9f5085159313" -dependencies = [ - "ark-ec", - "ark-serialize", - "ark-std", - "dleq_vrf 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "murmur-core", - "rand_core 0.6.4", - "w3f-bls", -] - [[package]] name = "nalgebra" version = "0.33.2" @@ -4277,65 +4053,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "pallet-beefy-etf" -version = "28.0.0" -dependencies = [ - "ark-bls12-377", - "ark-serialize", - "ark-std", - "frame-election-provider-support", - "frame-support 28.0.0", - "frame-system 28.0.0", - "getrandom 0.2.15", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-etf", - "pallet-offences", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "serde", - "sp-consensus-beefy-etf", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-beefy-mmr-etf" -version = "28.0.0" -dependencies = [ - "array-bytes 6.2.3", - "binary-merkle-tree 13.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-beefy-etf", - "pallet-etf", - "pallet-mmr", - "pallet-session", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-consensus-beefy-etf", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "pallet-drand" version = "0.0.1" @@ -4364,7 +4081,7 @@ dependencies = [ "sp-keyring", "sp-keystore 0.40.0", "sp-runtime 39.0.5", - "timelock 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "timelock", "w3f-bls", ] @@ -4375,8 +4092,8 @@ dependencies = [ "ark-bls12-377", "ark-serialize", "ark-std", - "array-bytes 6.2.3", - "binary-merkle-tree 13.0.0", + "array-bytes", + "binary-merkle-tree", "frame-election-provider-support", "frame-support 28.0.0", "frame-system 28.0.0", @@ -4384,8 +4101,6 @@ dependencies = [ "log", "pallet-authorship", "pallet-balances", - "pallet-beefy-etf", - "pallet-beefy-mmr-etf", "pallet-mmr", "pallet-offences", "pallet-session", @@ -4405,20 +4120,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "pallet-insecure-randomness-collective-flip" -version = "16.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-system 28.0.0", - "parity-scale-codec", - "safe-mix", - "scale-info", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "pallet-mmr" version = "27.0.0" @@ -4437,53 +4138,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "pallet-murmur" -version = "0.1.0-dev" -dependencies = [ - "ark-bls12-381", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf.git)", - "array-bytes 4.2.0", - "binary-merkle-tree 15.0.1", - "ckb-merkle-mountain-range", - "env_logger", - "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-support-test", - "frame-system 28.0.0", - "hex", - "log", - "murmur-core", - "murmur-test-utils", - "pallet-balances", - "pallet-beefy-etf", - "pallet-beefy-mmr-etf", - "pallet-etf", - "pallet-mmr", - "pallet-proxy", - "pallet-randomness-beacon", - "pallet-session", - "pallet-timestamp", - "parity-scale-codec", - "primitive-types 0.12.2", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "scale-info", - "serde", - "sha3", - "sp-consensus-beefy-etf", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "w3f-bls", -] - [[package]] name = "pallet-offences" version = "27.0.0" @@ -4501,40 +4155,6 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", ] -[[package]] -name = "pallet-preimage" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-proxy" -version = "0.1.0-dev" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "pallet-balances", - "pallet-utility", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "pallet-randomness-beacon" version = "1.0.0" @@ -4543,7 +4163,7 @@ dependencies = [ "ark-ff", "ark-serialize", "ark-std", - "array-bytes 6.2.3", + "array-bytes", "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", "frame-election-provider-support", "frame-support 28.0.0", @@ -4551,8 +4171,6 @@ dependencies = [ "log", "pallet-authorship", "pallet-balances", - "pallet-beefy-etf", - "pallet-beefy-mmr-etf", "pallet-etf", "pallet-mmr", "pallet-session", @@ -4575,39 +4193,6 @@ dependencies = [ "w3f-bls", ] -[[package]] -name = "pallet-scheduler" -version = "4.0.0-dev" -dependencies = [ - "ark-bls12-381", - "ark-crypto-primitives", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "docify", - "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-etf", - "pallet-insecure-randomness-collective-flip", - "pallet-preimage", - "pallet-randomness-beacon", - "pallet-timestamp", - "parity-scale-codec", - "rand_chacha 0.3.1", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-weights 27.0.0", - "substrate-test-utils", -] - [[package]] name = "pallet-session" version = "28.0.0" @@ -4683,22 +4268,6 @@ dependencies = [ "sp-timestamp", ] -[[package]] -name = "pallet-utility" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "parity-bip39" version = "2.0.1" @@ -5003,16 +4572,6 @@ dependencies = [ "zerocopy 0.7.35", ] -[[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - [[package]] name = "prettyplease" version = "0.2.25" @@ -5550,22 +5109,13 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver", ] [[package]] @@ -5671,15 +5221,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "safe-mix" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c" -dependencies = [ - "rustc_version 0.2.3", -] - [[package]] name = "safe_arch" version = "0.7.2" @@ -5824,27 +5365,12 @@ dependencies = [ "zeroize", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.215" @@ -6057,7 +5583,7 @@ dependencies = [ "curve25519-dalek", "rand_core 0.6.4", "ring 0.17.8", - "rustc_version 0.4.1", + "rustc_version", "sha2 0.10.8", "subtle", ] @@ -6253,7 +5779,7 @@ version = "13.0.0" dependencies = [ "ark-serialize", "ark-std", - "array-bytes 6.2.3", + "array-bytes", "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", "lazy_static", "parity-scale-codec", @@ -6278,7 +5804,7 @@ version = "1.0.0-dev" dependencies = [ "ark-bls12-381", "ark-serialize", - "array-bytes 6.2.3", + "array-bytes", "async-trait", "parity-scale-codec", "prost", @@ -6296,7 +5822,7 @@ version = "28.0.0" source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" dependencies = [ "ark-serialize", - "array-bytes 6.2.3", + "array-bytes", "bandersnatch_vrfs", "bitflags 1.3.2", "blake2", @@ -6345,7 +5871,7 @@ version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7" dependencies = [ - "array-bytes 6.2.3", + "array-bytes", "bitflags 1.3.2", "blake2", "bounded-collections", @@ -7343,15 +6869,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "substrate-test-utils" -version = "4.0.0-dev" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "futures", - "tokio", -] - [[package]] name = "subtle" version = "2.6.1" @@ -7424,12 +6941,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "target-triple" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" - [[package]] name = "tempfile" version = "3.14.0" @@ -7547,35 +7058,7 @@ dependencies = [ "ark-poly", "ark-serialize", "ark-std", - "array-bytes 6.2.3", - "chacha20poly1305", - "generic-array", - "parity-scale-codec", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "scale-info", - "serde", - "serde_cbor", - "serde_json", - "sha2 0.10.8", - "sha3", - "w3f-bls", -] - -[[package]] -name = "timelock" -version = "0.0.1" -source = "git+https://github.com/ideal-lab5/timelock.git#bcc5c5ae8c181e9f8ca4c919bb71d0dc89a9da1c" -dependencies = [ - "aes-gcm", - "ark-bls12-377", - "ark-bls12-381", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "array-bytes 6.2.3", + "array-bytes", "chacha20poly1305", "generic-array", "parity-scale-codec", @@ -7700,19 +7183,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "totp-rs" -version = "5.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b2f27dad992486c26b4e7455f38aa487e838d6d61b57e72906ee2b8c287a90" -dependencies = [ - "base32", - "constant_time_eq 0.2.6", - "hmac 0.12.1", - "sha1", - "sha2 0.10.8", -] - [[package]] name = "tower-service" version = "0.3.3" @@ -7818,22 +7288,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "trybuild" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" -dependencies = [ - "dissimilar", - "glob", - "serde", - "serde_derive", - "serde_json", - "target-triple", - "termcolor", - "toml", -] - [[package]] name = "tt-call" version = "1.0.9" @@ -8556,12 +8010,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - [[package]] name = "yasna" version = "0.5.2" diff --git a/Cargo.toml b/Cargo.toml index 53a0f3f..44652d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,9 @@ members = [ "client/consensus/randomness-beacon", "primitives/consensus/beefy-etf", "primitives/consensus/randomness-beacon", - "pallets/beefy-etf", - "pallets/beefy-mmr-etf", "pallets/drand", "pallets/etf", - "pallets/murmur", - "pallets/proxy", "pallets/randomness-beacon", - "pallets/scheduler", ] resolver = "2" diff --git a/pallets/beefy-etf/Cargo.toml b/pallets/beefy-etf/Cargo.toml deleted file mode 100644 index 9a6f8c9..0000000 --- a/pallets/beefy-etf/Cargo.toml +++ /dev/null @@ -1,87 +0,0 @@ -[package] -name = "pallet-beefy-etf" -version = "28.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -repository.workspace = true -description = "BEEFY FRAME pallet" -homepage = "https://substrate.io" - -[lints] -workspace = true - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { optional = true, workspace = true, default-features = true } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-authorship = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-etf = { path = "../etf", default-features = false} -pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -ark-serialize = { version = "0.4.0", default-features = false } -ark-std = { version = "0.4.0", default-features = false } -ark-bls12-377 = { version = "0.4.0", features = ["curve"], default-features = false } -getrandom = { version = "0.2", features = ["js"] } - -[dev-dependencies] -frame-election-provider-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-balances = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-offences = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking-reward-curve = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-timestamp = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -[features] -default = ["std"] -std = [ - "ark-std/std", - "ark-serialize/std", - "ark-bls12-377/std", - "codec/std", - "frame-election-provider-support/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-offences/std", - "pallet-etf/std", - "pallet-session/std", - "pallet-staking/std", - "pallet-timestamp/std", - "scale-info/std", - "serde/std", - "sp-consensus-beefy-etf/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-session/std", - "sp-staking/std", - "sp-state-machine/std", - "sp-std/std", -] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-offences/try-runtime", - "pallet-session/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/beefy-etf/src/default_weights.rs b/pallets/beefy-etf/src/default_weights.rs deleted file mode 100644 index 8042f0c..0000000 --- a/pallets/beefy-etf/src/default_weights.rs +++ /dev/null @@ -1,56 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! Default weights for the BEEFY Pallet -//! This file was not auto-generated. - -use frame_support::weights::{ - constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_MICROS, WEIGHT_REF_TIME_PER_NANOS}, - Weight, -}; - -impl crate::WeightInfo for () { - fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight { - // we take the validator set count from the membership proof to - // calculate the weight but we set a floor of 100 validators. - let validator_count = validator_count.max(100) as u64; - - // checking membership proof - Weight::from_parts(35u64 * WEIGHT_REF_TIME_PER_MICROS, 0) - .saturating_add( - Weight::from_parts(175u64 * WEIGHT_REF_TIME_PER_NANOS, 0) - .saturating_mul(validator_count), - ) - .saturating_add(DbWeight::get().reads(5)) - // check equivocation proof - .saturating_add(Weight::from_parts(95u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) - // report offence - .saturating_add(Weight::from_parts(110u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) - .saturating_add(Weight::from_parts( - 25u64 * WEIGHT_REF_TIME_PER_MICROS * max_nominators_per_validator as u64, - 0, - )) - .saturating_add(DbWeight::get().reads(14 + 3 * max_nominators_per_validator as u64)) - .saturating_add(DbWeight::get().writes(10 + 3 * max_nominators_per_validator as u64)) - // fetching set id -> session index mappings - .saturating_add(DbWeight::get().reads(2)) - } - - fn set_new_genesis() -> Weight { - DbWeight::get().writes(1) - } -} diff --git a/pallets/beefy-etf/src/equivocation.rs b/pallets/beefy-etf/src/equivocation.rs deleted file mode 100644 index 1487348..0000000 --- a/pallets/beefy-etf/src/equivocation.rs +++ /dev/null @@ -1,287 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! An opt-in utility module for reporting equivocations. -//! -//! This module defines an offence type for BEEFY equivocations -//! and some utility traits to wire together: -//! - a key ownership proof system (e.g. to prove that a given authority was part of a session); -//! - a system for reporting offences; -//! - a system for signing and submitting transactions; -//! - a way to get the current block author; -//! -//! These can be used in an offchain context in order to submit equivocation -//! reporting extrinsics (from the client that's running the BEEFY protocol). -//! And in a runtime context, so that the BEEFY pallet can validate the -//! equivocation proofs in the extrinsic and report the offences. -//! -//! IMPORTANT: -//! When using this module for enabling equivocation reporting it is required -//! that the `ValidateUnsigned` for the BEEFY pallet is used in the runtime -//! definition. - -use codec::{self as codec, Decode, Encode}; -use frame_support::traits::{Get, KeyOwnerProofSystem}; -use frame_system::pallet_prelude::BlockNumberFor; -use log::{error, info}; -use sp_consensus_beefy_etf::{EquivocationProof, ValidatorSetId, KEY_TYPE as BEEFY_KEY_TYPE}; -use sp_runtime::{ - transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, - TransactionValidityError, ValidTransaction, - }, - DispatchError, KeyTypeId, Perbill, RuntimeAppPublic, -}; -use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::{ - offence::{Kind, Offence, OffenceReportSystem, ReportOffence}, - SessionIndex, -}; -use sp_std::prelude::*; - -use super::{Call, Config, Error, Pallet, LOG_TARGET}; - -/// A round number and set id which point on the time of an offence. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] -pub struct TimeSlot { - // The order of these matters for `derive(Ord)`. - /// BEEFY Set ID. - pub set_id: ValidatorSetId, - /// Round number. - pub round: N, -} - -/// BEEFY equivocation offence report. -pub struct EquivocationOffence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - /// Time slot at which this incident happened. - pub time_slot: TimeSlot, - /// The session index in which the incident happened. - pub session_index: SessionIndex, - /// The size of the validator set at the time of the offence. - pub validator_set_count: u32, - /// The authority which produced this equivocation. - pub offender: Offender, -} - -impl Offence for EquivocationOffence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - const ID: Kind = *b"beefy:equivocati"; - type TimeSlot = TimeSlot; - - fn offenders(&self) -> Vec { - vec![self.offender.clone()] - } - - fn session_index(&self) -> SessionIndex { - self.session_index - } - - fn validator_set_count(&self) -> u32 { - self.validator_set_count - } - - fn time_slot(&self) -> Self::TimeSlot { - self.time_slot - } - - // The formula is min((3k / n)^2, 1) - // where k = offenders_number and n = validators_number - fn slash_fraction(&self, offenders_count: u32) -> Perbill { - // Perbill type domain is [0, 1] by definition - Perbill::from_rational(3 * offenders_count, self.validator_set_count).square() - } -} - -/// BEEFY equivocation offence report system. -/// -/// This type implements `OffenceReportSystem` such that: -/// - Equivocation reports are published on-chain as unsigned extrinsic via -/// `offchain::SendTransactionTypes`. -/// - On-chain validity checks and processing are mostly delegated to the user provided generic -/// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. -/// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. -pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); - -/// Equivocation evidence convenience alias. -pub type EquivocationEvidenceFor = ( - EquivocationProof< - BlockNumberFor, - ::BeefyId, - <::BeefyId as RuntimeAppPublic>::Signature, - >, - ::KeyOwnerProof, -); - -impl OffenceReportSystem, EquivocationEvidenceFor> - for EquivocationReportSystem -where - T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, - R: ReportOffence< - T::AccountId, - P::IdentificationTuple, - EquivocationOffence>, - >, - P: KeyOwnerProofSystem<(KeyTypeId, T::BeefyId), Proof = T::KeyOwnerProof>, - P::IdentificationTuple: Clone, - L: Get, -{ - type Longevity = L; - - fn publish_evidence(evidence: EquivocationEvidenceFor) -> Result<(), ()> { - use frame_system::offchain::SubmitTransaction; - let (equivocation_proof, key_owner_proof) = evidence; - - let call = Call::report_equivocation_unsigned { - equivocation_proof: Box::new(equivocation_proof), - key_owner_proof, - }; - - let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); - match res { - Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report."), - Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), - } - res - } - - fn check_evidence( - evidence: EquivocationEvidenceFor, - ) -> Result<(), TransactionValidityError> { - let (equivocation_proof, key_owner_proof) = evidence; - - // Check the membership proof to extract the offender's id - let key = (BEEFY_KEY_TYPE, equivocation_proof.offender_id().clone()); - let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?; - - // Check if the offence has already been reported, and if so then we can discard the report. - let time_slot = TimeSlot { - set_id: equivocation_proof.set_id(), - round: *equivocation_proof.round_number(), - }; - - if R::is_known_offence(&[offender], &time_slot) { - Err(InvalidTransaction::Stale.into()) - } else { - Ok(()) - } - } - - fn process_evidence( - reporter: Option, - evidence: EquivocationEvidenceFor, - ) -> Result<(), DispatchError> { - let (equivocation_proof, key_owner_proof) = evidence; - let reporter = reporter.or_else(|| pallet_authorship::Pallet::::author()); - let offender = equivocation_proof.offender_id().clone(); - - // We check the equivocation within the context of its set id (and - // associated session) and round. We also need to know the validator - // set count at the time of the offence since it is required to calculate - // the slash amount. - let set_id = equivocation_proof.set_id(); - let round = *equivocation_proof.round_number(); - let session_index = key_owner_proof.session(); - let validator_set_count = key_owner_proof.validator_count(); - - // Validate the key ownership proof extracting the id of the offender. - let offender = P::check_proof((BEEFY_KEY_TYPE, offender), key_owner_proof) - .ok_or(Error::::InvalidKeyOwnershipProof)?; - - // Validate equivocation proof (check votes are different and signatures are valid). - if !sp_consensus_beefy_etf::check_equivocation_proof(&equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()); - } - - // Check that the session id for the membership proof is within the - // bounds of the set id reported in the equivocation. - let set_id_session_index = - crate::SetIdSession::::get(set_id).ok_or(Error::::InvalidEquivocationProof)?; - if session_index != set_id_session_index { - return Err(Error::::InvalidEquivocationProof.into()); - } - - let offence = EquivocationOffence { - time_slot: TimeSlot { set_id, round }, - session_index, - validator_set_count, - offender, - }; - - R::report_offence(reporter.into_iter().collect(), offence) - .map_err(|_| Error::::DuplicateOffenceReport)?; - - Ok(()) - } -} - -/// Methods for the `ValidateUnsigned` implementation: -/// It restricts calls to `report_equivocation_unsigned` to local calls (i.e. extrinsics generated -/// on this node) or that already in a block. This guarantees that only block authors can include -/// unsigned equivocation reports. -impl Pallet { - pub fn validate_unsigned(source: TransactionSource, call: &Call) -> TransactionValidity { - if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { - // discard equivocation report not coming from the local node - match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, - _ => { - log::warn!( - target: LOG_TARGET, - "rejecting unsigned report equivocation transaction because it is not local/in-block." - ); - return InvalidTransaction::Call.into(); - }, - } - - let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); - T::EquivocationReportSystem::check_evidence(evidence)?; - - let longevity = - >::Longevity::get(); - - ValidTransaction::with_tag_prefix("BeefyEquivocation") - // We assign the maximum priority for any equivocation report. - .priority(TransactionPriority::MAX) - // Only one equivocation report for the same offender at the same slot. - .and_provides(( - equivocation_proof.offender_id().clone(), - equivocation_proof.set_id(), - *equivocation_proof.round_number(), - )) - .longevity(longevity) - // We don't propagate this. This can never be included on a remote node. - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - - pub fn pre_dispatch(call: &Call) -> Result<(), TransactionValidityError> { - if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { - let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); - T::EquivocationReportSystem::check_evidence(evidence) - } else { - Err(InvalidTransaction::Call.into()) - } - } -} diff --git a/pallets/beefy-etf/src/lib.rs b/pallets/beefy-etf/src/lib.rs deleted file mode 100644 index bcc7807..0000000 --- a/pallets/beefy-etf/src/lib.rs +++ /dev/null @@ -1,555 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![cfg_attr(not(feature = "std"), no_std)] -use codec::{Encode, MaxEncodedLen}; - -use frame_support::{ - dispatch::{DispatchResultWithPostInfo, Pays}, - pallet_prelude::*, - traits::{Get, OneSessionHandler}, - weights::Weight, - BoundedSlice, BoundedVec, Parameter, -}; -use frame_system::{ - ensure_none, ensure_signed, - pallet_prelude::{BlockNumberFor, OriginFor}, -}; -use log; -use sp_runtime::{ - generic::DigestItem, - traits::{IsMember, Member, One}, - RuntimeAppPublic, -}; -use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::{offence::OffenceReportSystem, SessionIndex}; -use sp_std::prelude::*; - -use sp_consensus_beefy_etf::{ - AuthorityIndex, BeefyAuthorityId, ConsensusLog, EquivocationProof, OnNewValidatorSet, - ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, -}; - -use pallet_etf::RoundCommitmentProvider; - -mod default_weights; -mod equivocation; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -pub use crate::equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot}; -pub use pallet::*; - -use crate::equivocation::EquivocationEvidenceFor; - -const LOG_TARGET: &str = "runtime::beefy"; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_system::{ensure_root, pallet_prelude::BlockNumberFor}; - - #[pallet::config] - pub trait Config: frame_system::Config { - /// Authority identifier type - type BeefyId: Member - + Parameter - // todo: use custom signature hashing type instead of hardcoded `Keccak256` - + BeefyAuthorityId - + MaybeSerializeDeserialize - + MaxEncodedLen; - - /// The maximum number of authorities that can be added. - #[pallet::constant] - type MaxAuthorities: Get; - - /// The maximum number of nominators for each validator. - #[pallet::constant] - type MaxNominators: Get; - - /// The maximum number of entries to keep in the set id to session index mapping. - /// - /// Since the `SetIdSession` map is only used for validating equivocations this - /// value should relate to the bonding duration of whatever staking system is - /// being used (if any). If equivocation handling is not enabled then this value - /// can be zero. - #[pallet::constant] - type MaxSetIdSessionEntries: Get; - - /// A hook to act on the new BEEFY validator set. - /// - /// For some applications it might be beneficial to make the BEEFY validator set available - /// externally apart from having it in the storage. For instance you might cache a light - /// weight MMR root over validators and make it available for Light Clients. - type OnNewValidatorSet: OnNewValidatorSet<::BeefyId>; - - /// Weights for this pallet. - type WeightInfo: WeightInfo; - - /// The proof of key ownership, used for validating equivocation reports - /// The proof must include the session index and validator count of the - /// session at which the equivocation occurred. - type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; - - /// The equivocation handling subsystem. - /// - /// Defines methods to publish, check and process an equivocation offence. - type EquivocationReportSystem: OffenceReportSystem< - Option, - EquivocationEvidenceFor, - >; - - /// Something that provides the round commitments for the current and next validator sets - type RoundCommitmentProvider: RoundCommitmentProvider; - } - - #[pallet::pallet] - pub struct Pallet(_); - - /// The current authorities set - #[pallet::storage] - pub type Authorities = - StorageValue<_, BoundedVec, ValueQuery>; - - /// The current validator set id - #[pallet::storage] - pub type ValidatorSetId = - StorageValue<_, sp_consensus_beefy_etf::ValidatorSetId, ValueQuery>; - - /// Authorities set scheduled to be used with the next session - #[pallet::storage] - pub type NextAuthorities = - StorageValue<_, BoundedVec, ValueQuery>; - - /// A mapping from BEEFY set ID to the index of the *most recent* session for which its - /// members were responsible. - /// - /// This is only used for validating equivocation proofs. An equivocation proof must - /// contains a key-ownership proof for a given session, therefore we need a way to tie - /// together sessions and BEEFY set ids, i.e. we need to validate that a validator - /// was the owner of a given key on a given session, and what the active set ID was - /// during that session. - /// - /// TWOX-NOTE: `ValidatorSetId` is not under user control. - #[pallet::storage] - pub type SetIdSession = - StorageMap<_, Twox64Concat, sp_consensus_beefy_etf::ValidatorSetId, SessionIndex>; - - /// Block number where BEEFY consensus is enabled/started. - /// By changing this (through privileged `set_new_genesis()`), BEEFY consensus is effectively - /// restarted from the newly set block number. - #[pallet::storage] - pub type GenesisBlock = StorageValue<_, Option>, ValueQuery>; - - #[pallet::genesis_config] - pub struct GenesisConfig { - /// Initial set of BEEFY authorities. - pub authorities: Vec, - /// Block number where BEEFY consensus should start. - /// Should match the session where initial authorities are active. - /// *Note:* Ideally use block number where GRANDPA authorities are changed, - /// to guarantee the client gets a finality notification for exactly this block. - pub genesis_block: Option>, - } - - impl Default for GenesisConfig { - fn default() -> Self { - // BEEFY genesis will be first BEEFY-MANDATORY block, - // use block number one instead of chain-genesis. - let genesis_block = Some(One::one()); - // by default, etf consensus will fail, must be intentionally seeded - Self { authorities: Vec::new(), genesis_block } - } - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - Pallet::::initialize(&self.authorities) - // we panic here as runtime maintainers can simply reconfigure genesis and restart - // the chain easily - .expect("Authorities vec too big"); - GenesisBlock::::put(&self.genesis_block); - } - } - - #[pallet::error] - pub enum Error { - /// A key ownership proof provided as part of an equivocation report is invalid. - InvalidKeyOwnershipProof, - /// An equivocation proof provided as part of an equivocation report is invalid. - InvalidEquivocationProof, - /// A given equivocation report is valid but already previously reported. - DuplicateOffenceReport, - /// Submitted configuration is invalid. - InvalidConfiguration, - } - - #[pallet::call] - impl Pallet { - /// Report voter equivocation/misbehavior. This method will verify the - /// equivocation proof and validate the given key ownership proof - /// against the extracted offender. If both are valid, the offence - /// will be reported. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::report_equivocation( - key_owner_proof.validator_count(), - T::MaxNominators::get(), - ))] - pub fn report_equivocation( - origin: OriginFor, - equivocation_proof: Box< - EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResultWithPostInfo { - let reporter = ensure_signed(origin)?; - - T::EquivocationReportSystem::process_evidence( - Some(reporter), - (*equivocation_proof, key_owner_proof), - )?; - // Waive the fee since the report is valid and beneficial - Ok(Pays::No.into()) - } - - /// Report voter equivocation/misbehavior. This method will verify the - /// equivocation proof and validate the given key ownership proof - /// against the extracted offender. If both are valid, the offence - /// will be reported. - /// - /// This extrinsic must be called unsigned and it is expected that only - /// block authors will call it (validated in `ValidateUnsigned`), as such - /// if the block author is defined it will be defined as the equivocation - /// reporter. - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::report_equivocation( - key_owner_proof.validator_count(), - T::MaxNominators::get(), - ))] - pub fn report_equivocation_unsigned( - origin: OriginFor, - equivocation_proof: Box< - EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResultWithPostInfo { - ensure_none(origin)?; - - T::EquivocationReportSystem::process_evidence( - None, - (*equivocation_proof, key_owner_proof), - )?; - Ok(Pays::No.into()) - } - - /// Reset BEEFY consensus by setting a new BEEFY genesis at `delay_in_blocks` blocks in the - /// future. - /// - /// Note: `delay_in_blocks` has to be at least 1. - #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::set_new_genesis())] - pub fn set_new_genesis( - origin: OriginFor, - delay_in_blocks: BlockNumberFor, - ) -> DispatchResult { - ensure_root(origin)?; - ensure!(delay_in_blocks >= One::one(), Error::::InvalidConfiguration); - let genesis_block = frame_system::Pallet::::block_number() + delay_in_blocks; - GenesisBlock::::put(Some(genesis_block)); - Ok(()) - } - } - - #[pallet::hooks] - impl Hooks> for Pallet { - #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state() - } - } - - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; - - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - Self::pre_dispatch(call) - } - - fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - Self::validate_unsigned(source, call) - } - } -} - -#[cfg(any(feature = "try-runtime", test))] -impl Pallet { - /// Ensure the correctness of the state of this pallet. - /// - /// This should be valid before or after each state transition of this pallet. - pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - Self::try_state_authorities()?; - Self::try_state_validators()?; - - Ok(()) - } - - /// # Invariants - /// - /// * `Authorities` should not exceed the `MaxAuthorities` capacity. - /// * `NextAuthorities` should not exceed the `MaxAuthorities` capacity. - fn try_state_authorities() -> Result<(), sp_runtime::TryRuntimeError> { - if let Some(authorities_len) = >::decode_len() { - ensure!( - authorities_len as u32 <= T::MaxAuthorities::get(), - "Authorities number exceeds what the pallet config allows." - ); - } else { - return Err(sp_runtime::TryRuntimeError::Other( - "Failed to decode length of authorities", - )); - } - - if let Some(next_authorities_len) = >::decode_len() { - ensure!( - next_authorities_len as u32 <= T::MaxAuthorities::get(), - "Next authorities number exceeds what the pallet config allows." - ); - } else { - return Err(sp_runtime::TryRuntimeError::Other( - "Failed to decode length of next authorities", - )); - } - Ok(()) - } - - /// # Invariants - /// - /// `ValidatorSetId` must be present in `SetIdSession` - fn try_state_validators() -> Result<(), sp_runtime::TryRuntimeError> { - let validator_set_id = >::get(); - ensure!( - SetIdSession::::get(validator_set_id).is_some(), - "Validator set id must be present in SetIdSession" - ); - Ok(()) - } -} - -impl Pallet { - /// Return the current validator set id - pub fn validator_set_id() -> sp_consensus_beefy_etf::ValidatorSetId { - >::get() - } - - /// Return the current active BEEFY validator set. - pub fn validator_set() -> Option> { - let validators: BoundedVec = Authorities::::get(); - let commitments: BoundedVec = - T::RoundCommitmentProvider::get(); - let id: sp_consensus_beefy_etf::ValidatorSetId = ValidatorSetId::::get(); - ValidatorSet::::new(validators, commitments, id) - } - - /// Submits an extrinsic to report an equivocation. This method will create - /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and - /// will push the transaction to the pool. Only useful in an offchain context. - pub fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> Option<()> { - T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok() - } - - // fn change_authorities( - // new: BoundedVec, - // queued: BoundedVec, - // ) { - // Authorities::::put(&new); - - // // for now.. never update the validator set id - // let new_id = ValidatorSetId::::get(); - // // let new_id = ValidatorSetId::::get() + 1u64; - // // ValidatorSetId::::put(new_id); - - // NextAuthorities::::put(&queued); - - // // TODO: for now we assume the commitments are static - // // we still need to implement authority rotation (ACSS Reshare + Recover - // let commitments: BoundedVec = - // T::RoundCommitmentProvider::get(); - - // if let Some(validator_set) = ValidatorSet::::new(new, commitments.clone(), - // new_id) { let log = DigestItem::Consensus( - // BEEFY_ENGINE_ID, - // ConsensusLog::AuthoritiesChange(validator_set.clone()).encode(), - // ); - // frame_system::Pallet::::deposit_log(log); - - // let next_id = new_id + 1; - // if let Some(next_validator_set) = ValidatorSet::::new(queued, commitments, - // next_id) { >::on_new_validator_set( - // &validator_set, - // &next_validator_set, - // ); - // } - // } - // } - - fn initialize(authorities: &Vec) -> Result<(), ()> { - if authorities.is_empty() { - return Ok(()); - } - - if !Authorities::::get().is_empty() { - return Err(()); - } - - let bounded_authorities = - BoundedSlice::::try_from(authorities.as_slice()) - .map_err(|_| ())?; - - let id = GENESIS_AUTHORITY_SET_ID; - Authorities::::put(bounded_authorities); - ValidatorSetId::::put(id); - // Like `pallet_session`, initialize the next validator set as well. - NextAuthorities::::put(bounded_authorities); - - let public_commitments: Vec = T::RoundCommitmentProvider::get().into(); - - if let Some(validator_set) = - ValidatorSet::::new(authorities.clone(), public_commitments.clone(), id) - { - let next_id = id + 1; - if let Some(next_validator_set) = - ValidatorSet::::new(authorities.clone(), public_commitments, next_id) - { - >::on_new_validator_set( - &validator_set, - &next_validator_set, - ); - } - } - - // NOTE: initialize first session of first set. this is necessary for - // the genesis set and session since we only update the set -> session - // mapping whenever a new session starts, i.e. through `on_new_session`. - SetIdSession::::insert(0, 0); - - Ok(()) - } -} - -impl sp_runtime::BoundToRuntimeAppPublic for Pallet { - type Public = T::BeefyId; -} - -impl OneSessionHandler for Pallet -where - T: pallet_session::Config, -{ - type Key = T::BeefyId; - - fn on_genesis_session<'a, I: 'a>(validators: I) - where - I: Iterator, - { - let authorities = validators.map(|(_, k)| k).collect::>(); - // we panic here as runtime maintainers can simply reconfigure genesis and restart the - // chain easily - Self::initialize(&authorities).expect("Authorities vec too big"); - } - - fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) - where - I: Iterator, - { - let next_authorities = validators.map(|(_, k)| k).collect::>(); - if next_authorities.len() as u32 > T::MaxAuthorities::get() { - log::error!( - target: LOG_TARGET, - "authorities list {:?} truncated to length {}", - next_authorities, - T::MaxAuthorities::get(), - ); - } - // let bounded_next_authorities = - // BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_authorities); - - let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::>(); - if next_queued_authorities.len() as u32 > T::MaxAuthorities::get() { - log::error!( - target: LOG_TARGET, - "queued authorities list {:?} truncated to length {}", - next_queued_authorities, - T::MaxAuthorities::get(), - ); - } - // let bounded_next_queued_authorities = - // BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_queued_authorities); - - // Always issue a change on each `session`, even if validator set hasn't changed. - // We want to have at least one BEEFY mandatory block per session. - // temporarily disabling this call - // Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities); - - let validator_set_id = ValidatorSetId::::get(); - // Update the mapping for the new set id that corresponds to the latest session (i.e. now). - let session_index = pallet_session::Pallet::::current_index(); - SetIdSession::::insert(validator_set_id, &session_index); - // Prune old entry if limit reached. - let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1); - if validator_set_id >= max_set_id_session_entries { - SetIdSession::::remove(validator_set_id - max_set_id_session_entries); - } - } - - fn on_disabled(i: u32) { - let log = DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), - ); - - frame_system::Pallet::::deposit_log(log); - } -} - -impl IsMember for Pallet { - fn is_member(authority_id: &T::BeefyId) -> bool { - Authorities::::get().iter().any(|id| id == authority_id) - } -} - -pub trait WeightInfo { - fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight; - fn set_new_genesis() -> Weight; -} diff --git a/pallets/beefy-etf/src/mock.rs b/pallets/beefy-etf/src/mock.rs deleted file mode 100644 index 1ba4a1e..0000000 --- a/pallets/beefy-etf/src/mock.rs +++ /dev/null @@ -1,359 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use std::vec; - -use frame_election_provider_support::{ - bounds::{ElectionBounds, ElectionBoundsBuilder}, - onchain, SequentialPhragmen, -}; -use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ConstU32, ConstU64, KeyOwnerProofSystem, OnFinalize, OnInitialize}, -}; -use pallet_session::historical as pallet_session_historical; -use sp_core::{crypto::KeyTypeId, ConstU128}; -use sp_runtime::{ - app_crypto::bls377::Public, curve::PiecewiseLinear, impl_opaque_keys, testing::TestXt, - traits::OpaqueKeys, BuildStorage, Perbill, -}; -use sp_staking::{EraIndex, SessionIndex}; -use sp_state_machine::BasicExternalities; - -use crate as pallet_beefy; - -// #[cfg(feature = "bls-experimental")] -pub use sp_consensus_beefy_etf::bls_crypto::AuthorityId as BeefyId; - -// #[cfg(not(feature = "bls-experimental"))] -// pub use sp_consensus_beefy_etf::ecdsa_crypto::AuthorityId as BeefyId; - -pub use sp_consensus_beefy_etf::{ConsensusLog, BEEFY_ENGINE_ID}; - -impl_opaque_keys! { - pub struct MockSessionKeys { - pub dummy: pallet_beefy::Pallet, - } -} - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Test - { - System: frame_system, - Authorship: pallet_authorship, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - Etf: pallet_etf, - Beefy: pallet_beefy, - Staking: pallet_staking, - Session: pallet_session, - Offences: pallet_offences, - Historical: pallet_session_historical, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -impl frame_system::offchain::SendTransactionTypes for Test -where - RuntimeCall: From, -{ - type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; -} - -parameter_types! { - pub const Period: u64 = 1; - pub const ReportLongevity: u64 = - BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); - pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); -} - -impl pallet_etf::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; -} - -impl pallet_beefy::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; - type MaxNominators = ConstU32<1000>; - type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - type OnNewValidatorSet = (); - type WeightInfo = (); - type KeyOwnerProof = >::Proof; - type EquivocationReportSystem = - super::EquivocationReportSystem; - type RoundCommitmentProvider = Etf; -} - -parameter_types! { - pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); -} - -impl pallet_session::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = u64; - type ValidatorIdOf = pallet_staking::StashOf; - type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = MockSessionKeys; - type WeightInfo = (); -} - -impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -impl pallet_authorship::Config for Test { - type FindAuthor = (); - type EventHandler = (); -} - -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = u128; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU128<1>; - type AccountStore = System; - type WeightInfo = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); - type FreezeIdentifier = (); - type MaxFreezes = (); -} - -impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<3>; - type WeightInfo = (); -} - -pallet_staking_reward_curve::build! { - const REWARD_CURVE: PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000u64, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} - -parameter_types! { - pub const SessionsPerEra: SessionIndex = 3; - pub const BondingDuration: EraIndex = 3; - pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); - pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); -} - -pub struct OnChainSeqPhragmen; -impl onchain::Config for OnChainSeqPhragmen { - type System = Test; - type Solver = SequentialPhragmen; - type DataProvider = Staking; - type WeightInfo = (); - type MaxWinners = ConstU32<100>; - type Bounds = ElectionsBoundsOnChain; -} - -impl pallet_staking::Config for Test { - type RewardRemainder = (); - type CurrencyToVote = (); - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type CurrencyBalance = ::Balance; - type Slash = (); - type Reward = (); - type SessionsPerEra = SessionsPerEra; - type BondingDuration = BondingDuration; - type SlashDeferDuration = (); - type AdminOrigin = frame_system::EnsureRoot; - type SessionInterface = Self; - type UnixTime = pallet_timestamp::Pallet; - type EraPayout = pallet_staking::ConvertCurve; - type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type NextNewSession = Session; - type ElectionProvider = onchain::OnChainExecution; - type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; - type TargetList = pallet_staking::UseValidatorsMap; - type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; - type MaxUnlockingChunks = ConstU32<32>; - type MaxControllersInDeprecationBatch = ConstU32<100>; - type HistoryDepth = ConstU32<84>; - type EventListeners = (); - type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; - type WeightInfo = (); -} - -impl pallet_offences::Config for Test { - type RuntimeEvent = RuntimeEvent; - type IdentificationTuple = pallet_session::historical::IdentificationTuple; - type OnOffenceHandler = Staking; -} - -#[derive(Default)] -pub struct ExtBuilder { - authorities: Vec, - commitments: Vec, -} - -impl ExtBuilder { - /// Add some AccountIds to insert into `List`. - #[cfg(test)] - pub(crate) fn add_authorities(mut self, ids: Vec) -> Self { - self.authorities = ids; - self - } - - // Add some commitments (AccountIds) to insert into storage - #[cfg(test)] - pub(crate) fn add_commitments(mut self, ids: Vec) -> Self { - self.commitments = ids; - self - } - - pub fn build(self) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let balances: Vec<_> = - (0..self.authorities.len()).map(|i| (i as u64, 10_000_000)).collect(); - - pallet_balances::GenesisConfig:: { balances } - .assimilate_storage(&mut t) - .unwrap(); - - let session_keys: Vec<_> = self - .authorities - .iter() - .enumerate() - .map(|(i, k)| (i as u64, i as u64, MockSessionKeys { dummy: k.clone() })) - .collect(); - - BasicExternalities::execute_with_storage(&mut t, || { - for (ref id, ..) in &session_keys { - frame_system::Pallet::::inc_providers(id); - } - }); - - pallet_session::GenesisConfig:: { keys: session_keys } - .assimilate_storage(&mut t) - .unwrap(); - - let genesis_resharing = - self.commitments.iter().map(|comm| (comm.clone(), vec![2])).collect(); - - pallet_etf::GenesisConfig:: { genesis_resharing, round_pubkey: vec![1] } - .assimilate_storage(&mut t) - .unwrap(); - - // controllers are same as stash - let stakers: Vec<_> = (0..self.authorities.len()) - .map(|i| (i as u64, i as u64, 10_000, pallet_staking::StakerStatus::::Validator)) - .collect(); - - let staking_config = pallet_staking::GenesisConfig:: { - stakers, - validator_count: 2, - force_era: pallet_staking::Forcing::ForceNew, - minimum_validator_count: 0, - invulnerables: vec![], - ..Default::default() - }; - - staking_config.assimilate_storage(&mut t).unwrap(); - - let beefy_config = - pallet_beefy::GenesisConfig:: { authorities: vec![], genesis_block: None }; - - beefy_config.assimilate_storage(&mut t).unwrap(); - - t.into() - } - - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - self.build().execute_with(|| { - test(); - Beefy::do_try_state().expect("All invariants must hold after a test"); - }) - } -} - -// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation -// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, -// with the first one containing information to reconstruct the uncompressed key. -pub fn mock_beefy_id(id: u8) -> BeefyId { - let mut buf: [u8; 144] = [id; 144]; - // Set to something valid. - buf[0] = 0x02; - let pk = Public::from_raw(buf); - BeefyId::from(pk) -} - -pub fn mock_authorities(vec: Vec) -> Vec { - vec.into_iter().map(|id| mock_beefy_id(id)).collect() -} - -pub fn start_session(session_index: SessionIndex) { - for i in Session::current_index()..session_index { - System::on_finalize(System::block_number()); - Session::on_finalize(System::block_number()); - Staking::on_finalize(System::block_number()); - Beefy::on_finalize(System::block_number()); - - let parent_hash = if System::block_number() > 1 { - let hdr = System::finalize(); - hdr.hash() - } else { - System::parent_hash() - }; - - System::reset_events(); - System::initialize(&(i as u64 + 1), &parent_hash, &Default::default()); - System::set_block_number((i + 1).into()); - Timestamp::set_timestamp(System::block_number() * 6000); - - System::on_initialize(System::block_number()); - Session::on_initialize(System::block_number()); - Staking::on_initialize(System::block_number()); - Beefy::on_initialize(System::block_number()); - } - - assert_eq!(Session::current_index(), session_index); -} - -pub fn start_era(era_index: EraIndex) { - start_session((era_index * 3).into()); - assert_eq!(Staking::current_era(), Some(era_index)); -} diff --git a/pallets/beefy-etf/src/tests.rs b/pallets/beefy-etf/src/tests.rs deleted file mode 100644 index 9f6701a..0000000 --- a/pallets/beefy-etf/src/tests.rs +++ /dev/null @@ -1,864 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. -use codec::Encode; -use std::vec; - -use frame_support::{ - assert_err, assert_ok, - dispatch::{GetDispatchInfo, Pays}, - traits::{Currency, KeyOwnerProofSystem, OnInitialize}, -}; -use sp_consensus_beefy_etf::{ - check_equivocation_proof, - known_payloads::MMR_ROOT_ID, - test_utils::{generate_equivocation_proof, Keyring as BeefyKeyring}, - Payload, ValidatorSet, KEY_TYPE as BEEFY_KEY_TYPE, -}; -use sp_runtime::DigestItem; - -use crate::{self as beefy, mock::*, Call, Config, Error, Weight, WeightInfo}; - -fn init_block(block: u64) { - System::set_block_number(block); - Session::on_initialize(block); -} - -pub fn beefy_log(log: ConsensusLog) -> DigestItem { - DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) -} - -#[test] -fn genesis_session_initializes_authorities() { - let authorities = mock_authorities(vec![1, 2, 3, 4]); - let want = authorities.clone(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - let authorities = beefy::Authorities::::get(); - - assert_eq!(authorities.len(), 4); - assert_eq!(want[0], authorities[0]); - assert_eq!(want[1], authorities[1]); - - assert!(beefy::ValidatorSetId::::get() == 0); - - let next_authorities = beefy::NextAuthorities::::get(); - - assert_eq!(next_authorities.len(), 4); - assert_eq!(want[0], next_authorities[0]); - assert_eq!(want[1], next_authorities[1]); - }); -} - -#[test] -fn session_change_updates_authorities() { - let authorities = mock_authorities(vec![1, 2, 3, 4]); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities.clone()) - .build_and_execute(|| { - assert!(0 == beefy::ValidatorSetId::::get()); - - init_block(1); - - assert!(1 == beefy::ValidatorSetId::::get()); - - let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(authorities.clone(), authorities.clone(), 1).unwrap(), - )); - - let log = System::digest().logs[0].clone(); - assert_eq!(want, log); - - init_block(2); - - assert!(2 == beefy::ValidatorSetId::::get()); - - let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(vec![mock_beefy_id(2), mock_beefy_id(4)], authorities.clone(), 2) - .unwrap(), - )); - - let log = System::digest().logs[1].clone(); - assert_eq!(want, log); - }); -} - -#[test] -fn session_change_updates_next_authorities() { - let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; - - let authorities = mock_authorities(vec![1, 2, 3, 4]); - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - let next_authorities = beefy::NextAuthorities::::get(); - - assert_eq!(next_authorities.len(), 4); - assert_eq!(want[0], next_authorities[0]); - assert_eq!(want[1], next_authorities[1]); - assert_eq!(want[2], next_authorities[2]); - assert_eq!(want[3], next_authorities[3]); - - init_block(1); - - let next_authorities = beefy::NextAuthorities::::get(); - - assert_eq!(next_authorities.len(), 2); - assert_eq!(want[1], next_authorities[0]); - assert_eq!(want[3], next_authorities[1]); - }); -} - -#[test] -fn validator_set_at_genesis() { - let want = vec![mock_beefy_id(1), mock_beefy_id(2)]; - - let authorities = mock_authorities(vec![1, 2, 3, 4]); - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - let vs = Beefy::validator_set().unwrap(); - - assert_eq!(vs.id(), 0u64); - assert_eq!(vs.validators()[0], want[0]); - assert_eq!(vs.validators()[1], want[1]); - }); -} - -#[test] -fn validator_set_updates_work() { - let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; - - let authorities = mock_authorities(vec![1, 2, 3, 4]); - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 0u64); - assert_eq!(want[0], vs.validators()[0]); - assert_eq!(want[1], vs.validators()[1]); - assert_eq!(want[2], vs.validators()[2]); - assert_eq!(want[3], vs.validators()[3]); - - init_block(1); - - let vs = Beefy::validator_set().unwrap(); - - assert_eq!(vs.id(), 1u64); - assert_eq!(want[0], vs.validators()[0]); - assert_eq!(want[1], vs.validators()[1]); - - init_block(2); - - let vs = Beefy::validator_set().unwrap(); - - assert_eq!(vs.id(), 2u64); - assert_eq!(want[1], vs.validators()[0]); - assert_eq!(want[3], vs.validators()[1]); - }); -} - -#[test] -fn cleans_up_old_set_id_session_mappings() { - let authorities = mock_authorities(vec![1, 2, 3, 4]); - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - let max_set_id_session_entries = MaxSetIdSessionEntries::get(); - - // we have 3 sessions per era - let era_limit = max_set_id_session_entries / 3; - // sanity check against division precision loss - assert_eq!(0, max_set_id_session_entries % 3); - // go through `max_set_id_session_entries` sessions - start_era(era_limit); - - // we should have a session id mapping for all the set ids from - // `max_set_id_session_entries` eras we have observed - for i in 1..=max_set_id_session_entries { - assert!(beefy::SetIdSession::::get(i as u64).is_some()); - } - - // go through another `max_set_id_session_entries` sessions - start_era(era_limit * 2); - - // we should keep tracking the new mappings for new sessions - for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { - assert!(beefy::SetIdSession::::get(i as u64).is_some()); - } - - // but the old ones should have been pruned by now - for i in 1..=max_set_id_session_entries { - assert!(beefy::SetIdSession::::get(i as u64).is_none()); - } - }); -} - -/// Returns a list with 3 authorities with known keys: -/// Alice, Bob and Charlie. -pub fn test_authorities() -> Vec { - let authorities = vec![BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; - authorities.into_iter().map(|id| id.public()).collect() -} - -#[test] -fn should_sign_and_verify() { - use sp_runtime::traits::Keccak256; - - let set_id = 3; - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - - // generate an equivocation proof, with two votes in the same round for - // same payload signed by the same key - let equivocation_proof = generate_equivocation_proof( - (1, payload1.clone(), set_id, &BeefyKeyring::Bob), - (1, payload1.clone(), set_id, &BeefyKeyring::Bob), - ); - // expect invalid equivocation proof - assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); - - // generate an equivocation proof, with two votes in different rounds for - // different payloads signed by the same key - let equivocation_proof = generate_equivocation_proof( - (1, payload1.clone(), set_id, &BeefyKeyring::Bob), - (2, payload2.clone(), set_id, &BeefyKeyring::Bob), - ); - // expect invalid equivocation proof - assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); - - // generate an equivocation proof, with two votes by different authorities - let equivocation_proof = generate_equivocation_proof( - (1, payload1.clone(), set_id, &BeefyKeyring::Alice), - (1, payload2.clone(), set_id, &BeefyKeyring::Bob), - ); - // expect invalid equivocation proof - assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); - - // generate an equivocation proof, with two votes in different set ids - let equivocation_proof = generate_equivocation_proof( - (1, payload1.clone(), set_id, &BeefyKeyring::Bob), - (1, payload2.clone(), set_id + 1, &BeefyKeyring::Bob), - ); - // expect invalid equivocation proof - assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); - - // generate an equivocation proof, with two votes in the same round for - // different payloads signed by the same key - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - let equivocation_proof = generate_equivocation_proof( - (1, payload1, set_id, &BeefyKeyring::Bob), - (1, payload2, set_id, &BeefyKeyring::Bob), - ); - // expect valid equivocation proof - assert!(check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); -} - -#[test] -fn report_equivocation_current_set_works() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities.clone()) - .build_and_execute(|| { - assert_eq!(Staking::current_era(), Some(0)); - assert_eq!(Session::current_index(), 0); - - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - let validators = Session::validators(); - - // make sure that all validators have the same balance - for validator in &validators { - assert_eq!(Balances::total_balance(validator), 10_000_000); - assert_eq!(Staking::slashable_balance_of(validator), 10_000); - - assert_eq!( - Staking::eras_stakers(1, &validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, - ); - } - - assert_eq!(authorities.len(), 2); - let equivocation_authority_index = 1; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - // generate an equivocation proof, with two votes in the same round for - // different payloads signed by the same key - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id, &equivocation_keyring), - (block_num, payload2, set_id, &equivocation_keyring), - ); - - // create the key ownership proof - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - // report the equivocation and the tx should be dispatched successfully - assert_ok!(Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ),); - - start_era(2); - - // check that the balance of 0-th validator is slashed 100%. - let equivocation_validator_id = validators[equivocation_authority_index]; - - assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); - assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); - assert_eq!( - Staking::eras_stakers(2, &equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, - ); - - // check that the balances of all other validators are left intact. - for validator in &validators { - if *validator == equivocation_validator_id { - continue; - } - - assert_eq!(Balances::total_balance(validator), 10_000_000); - assert_eq!(Staking::slashable_balance_of(validator), 10_000); - - assert_eq!( - Staking::eras_stakers(2, &validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, - ); - } - }); -} - -#[test] -fn report_equivocation_old_set_works() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let validators = Session::validators(); - let old_set_id = validator_set.id(); - - assert_eq!(authorities.len(), 2); - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - - // create the key ownership proof in the "old" set - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - start_era(2); - - // make sure that all authorities have the same balance - for validator in &validators { - assert_eq!(Balances::total_balance(validator), 10_000_000); - assert_eq!(Staking::slashable_balance_of(validator), 10_000); - - assert_eq!( - Staking::eras_stakers(2, &validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, - ); - } - - let validator_set = Beefy::validator_set().unwrap(); - let new_set_id = validator_set.id(); - assert_eq!(old_set_id + 3, new_set_id); - - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - // generate an equivocation proof for the old set, - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, old_set_id, &equivocation_keyring), - (block_num, payload2, old_set_id, &equivocation_keyring), - ); - - // report the equivocation and the tx should be dispatched successfully - assert_ok!(Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ),); - - start_era(3); - - // check that the balance of 0-th validator is slashed 100%. - let equivocation_validator_id = validators[equivocation_authority_index]; - - assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); - assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); - assert_eq!( - Staking::eras_stakers(3, &equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, - ); - - // check that the balances of all other validators are left intact. - for validator in &validators { - if *validator == equivocation_validator_id { - continue; - } - - assert_eq!(Balances::total_balance(validator), 10_000_000); - assert_eq!(Staking::slashable_balance_of(validator), 10_000); - - assert_eq!( - Staking::eras_stakers(3, &validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, - ); - } - }); -} - -#[test] -fn report_equivocation_invalid_set_id() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - // generate an equivocation for a future set - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id + 1, &equivocation_keyring), - (block_num, payload2, set_id + 1, &equivocation_keyring), - ); - - // the call for reporting the equivocation should error - assert_err!( - Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ), - Error::::InvalidEquivocationProof, - ); - }); -} - -#[test] -fn report_equivocation_invalid_session() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - // generate a key ownership proof at current era set id - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - start_era(2); - - let set_id = Beefy::validator_set().unwrap().id(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - // generate an equivocation proof at following era set id = 2 - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id, &equivocation_keyring), - (block_num, payload2, set_id, &equivocation_keyring), - ); - - // report an equivocation for the current set using an key ownership - // proof from the previous set, the session should be invalid. - assert_err!( - Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ), - Error::::InvalidEquivocationProof, - ); - }); -} - -#[test] -fn report_equivocation_invalid_key_owner_proof() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - - let invalid_owner_authority_index = 1; - let invalid_owner_key = &authorities[invalid_owner_authority_index]; - - // generate a key ownership proof for the authority at index 1 - let invalid_key_owner_proof = - Historical::prove((BEEFY_KEY_TYPE, &invalid_owner_key)).unwrap(); - - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - // generate an equivocation proof for the authority at index 0 - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id + 1, &equivocation_keyring), - (block_num, payload2, set_id + 1, &equivocation_keyring), - ); - - // we need to start a new era otherwise the key ownership proof won't be - // checked since the authorities are part of the current session - start_era(2); - - // report an equivocation for the current set using a key ownership - // proof for a different key than the one in the equivocation proof. - assert_err!( - Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - invalid_key_owner_proof, - ), - Error::::InvalidKeyOwnershipProof, - ); - }); -} - -#[test] -fn report_equivocation_invalid_equivocation_proof() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - // generate a key ownership proof at set id in era 1 - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - let assert_invalid_equivocation_proof = |equivocation_proof| { - assert_err!( - Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof.clone(), - ), - Error::::InvalidEquivocationProof, - ); - }; - - start_era(2); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - - // both votes target the same block number and payload, - // there is no equivocation. - assert_invalid_equivocation_proof(generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &equivocation_keyring), - (block_num, payload1.clone(), set_id, &equivocation_keyring), - )); - - // votes targeting different rounds, there is no equivocation. - assert_invalid_equivocation_proof(generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &equivocation_keyring), - (block_num + 1, payload2.clone(), set_id, &equivocation_keyring), - )); - - // votes signed with different authority keys - assert_invalid_equivocation_proof(generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &equivocation_keyring), - (block_num, payload1.clone(), set_id, &BeefyKeyring::Charlie), - )); - - // votes signed with a key that isn't part of the authority set - assert_invalid_equivocation_proof(generate_equivocation_proof( - (block_num, payload1.clone(), set_id, &equivocation_keyring), - (block_num, payload1.clone(), set_id, &BeefyKeyring::Dave), - )); - - // votes targeting different set ids - assert_invalid_equivocation_proof(generate_equivocation_proof( - (block_num, payload1, set_id, &equivocation_keyring), - (block_num, payload2, set_id + 1, &equivocation_keyring), - )); - }); -} - -#[test] -fn report_equivocation_validate_unsigned_prevents_duplicates() { - use sp_runtime::transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, - ValidTransaction, - }; - - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - - // generate and report an equivocation for the validator at index 0 - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id, &equivocation_keyring), - (block_num, payload2, set_id, &equivocation_keyring), - ); - - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - let call = Call::report_equivocation_unsigned { - equivocation_proof: Box::new(equivocation_proof.clone()), - key_owner_proof: key_owner_proof.clone(), - }; - - // only local/inblock reports are allowed - assert_eq!( - ::validate_unsigned( - TransactionSource::External, - &call, - ), - InvalidTransaction::Call.into(), - ); - - // the transaction is valid when passed as local - let tx_tag = (equivocation_key, set_id, 3u64); - - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &call, - ), - TransactionValidity::Ok(ValidTransaction { - priority: TransactionPriority::max_value(), - requires: vec![], - provides: vec![("BeefyEquivocation", tx_tag).encode()], - longevity: ReportLongevity::get(), - propagate: false, - }) - ); - - // the pre dispatch checks should also pass - assert_ok!(::pre_dispatch(&call)); - - // we submit the report - Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ) - .unwrap(); - - // the report should now be considered stale and the transaction is invalid - // the check for staleness should be done on both `validate_unsigned` and on - // `pre_dispatch` - assert_err!( - ::validate_unsigned( - TransactionSource::Local, - &call, - ), - InvalidTransaction::Stale, - ); - - assert_err!( - ::pre_dispatch(&call), - InvalidTransaction::Stale, - ); - }); -} - -#[test] -fn report_equivocation_has_valid_weight() { - // the weight depends on the size of the validator set, - // but there's a lower bound of 100 validators. - assert!((1..=100) - .map(|validators| ::WeightInfo::report_equivocation(validators, 1000)) - .collect::>() - .windows(2) - .all(|w| w[0] == w[1])); - - // after 100 validators the weight should keep increasing - // with every extra validator. - assert!((100..=1000) - .map(|validators| ::WeightInfo::report_equivocation(validators, 1000)) - .collect::>() - .windows(2) - .all(|w| w[0].ref_time() < w[1].ref_time())); -} - -#[test] -fn valid_equivocation_reports_dont_pay_fees() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let block_num = System::block_number(); - let validator_set = Beefy::validator_set().unwrap(); - let authorities = validator_set.validators(); - let set_id = validator_set.id(); - - let equivocation_authority_index = 0; - let equivocation_key = &authorities[equivocation_authority_index]; - let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - - // generate equivocation proof - let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); - let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); - let equivocation_proof = generate_equivocation_proof( - (block_num, payload1, set_id, &equivocation_keyring), - (block_num, payload2, set_id, &equivocation_keyring), - ); - - // create the key ownership proof. - let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); - - // check the dispatch info for the call. - let info = Call::::report_equivocation_unsigned { - equivocation_proof: Box::new(equivocation_proof.clone()), - key_owner_proof: key_owner_proof.clone(), - } - .get_dispatch_info(); - - // it should have non-zero weight and the fee has to be paid. - assert!(info.weight.any_gt(Weight::zero())); - assert_eq!(info.pays_fee, Pays::Yes); - - // report the equivocation. - let post_info = Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof.clone()), - key_owner_proof.clone(), - ) - .unwrap(); - - // the original weight should be kept, but given that the report - // is valid the fee is waived. - assert!(post_info.actual_weight.is_none()); - assert_eq!(post_info.pays_fee, Pays::No); - - // report the equivocation again which is invalid now since it is - // duplicate. - let post_info = Beefy::report_equivocation_unsigned( - RuntimeOrigin::none(), - Box::new(equivocation_proof), - key_owner_proof, - ) - .err() - .unwrap() - .post_info; - - // the fee is not waived and the original weight is kept. - assert!(post_info.actual_weight.is_none()); - assert_eq!(post_info.pays_fee, Pays::Yes); - }) -} - -#[test] -fn set_new_genesis_works() { - let authorities = test_authorities(); - - ExtBuilder::default() - .add_authorities(authorities.clone()) - .add_commitments(authorities) - .build_and_execute(|| { - start_era(1); - - let new_genesis_delay = 10u64; - // the call for setting new genesis should work - assert_ok!(Beefy::set_new_genesis(RuntimeOrigin::root(), new_genesis_delay,)); - let expected = System::block_number() + new_genesis_delay; - // verify new genesis was set - assert_eq!(beefy::GenesisBlock::::get(), Some(expected)); - - // setting delay < 1 should fail - assert_err!( - Beefy::set_new_genesis(RuntimeOrigin::root(), 0u64,), - Error::::InvalidConfiguration, - ); - }); -} diff --git a/pallets/beefy-mmr-etf/Cargo.toml b/pallets/beefy-mmr-etf/Cargo.toml deleted file mode 100644 index 4893b69..0000000 --- a/pallets/beefy-mmr-etf/Cargo.toml +++ /dev/null @@ -1,69 +0,0 @@ -[package] -name = "pallet-beefy-mmr-etf" -version = "28.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "BEEFY + MMR runtime utilities" -repository.workspace = true -homepage.workspace = true - -[lints] -workspace = true - -[dependencies] -array-bytes = { version = "6.1", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { optional = true, workspace = true, default-features = true } -binary-merkle-tree = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-beefy = { package = "pallet-beefy-etf", path = "../beefy-etf", default-features = false } -pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-api = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -[dev-dependencies] -array-bytes = "6.1" -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-etf = { path = "../etf" } - -[features] -default = ["std"] -std = [ - "array-bytes", - "binary-merkle-tree/std", - "codec/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-beefy/std", - "pallet-mmr/std", - "pallet-session/std", - "scale-info/std", - "serde", - "sp-api/std", - "sp-consensus-beefy-etf/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-staking/std", - "sp-state-machine/std", - "sp-std/std", -] -try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-beefy/try-runtime", - "pallet-mmr/try-runtime", - "pallet-session/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/beefy-mmr-etf/src/lib.rs b/pallets/beefy-mmr-etf/src/lib.rs deleted file mode 100644 index 5b2c22e..0000000 --- a/pallets/beefy-mmr-etf/src/lib.rs +++ /dev/null @@ -1,255 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![cfg_attr(not(feature = "std"), no_std)] -#![warn(missing_docs)] - -//! A BEEFY+MMR pallet combo. -//! -//! While both BEEFY and Merkle Mountain Range (MMR) can be used separately, -//! these tools were designed to work together in unison. -//! -//! The pallet provides a standardized MMR Leaf format that can be used -//! to bridge BEEFY+MMR-based networks (both standalone and Polkadot-like). -//! -//! The MMR leaf contains: -//! 1. Block number and parent block hash. -//! 2. Merkle Tree Root Hash of next BEEFY validator set. -//! 3. Arbitrary extra leaf data to be used by downstream pallets to include custom data. -//! -//! and thanks to versioning can be easily updated in the future. - -use sp_runtime::traits::{Convert, Member}; -use sp_std::prelude::*; - -use codec::Decode; -use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; -use sp_consensus_beefy_etf::{ - mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}, - ValidatorSet as BeefyValidatorSet, -}; - -use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get}; -use frame_system::pallet_prelude::BlockNumberFor; - -pub use pallet::*; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -/// A BEEFY consensus digest item with MMR root hash. -pub struct DepositBeefyDigest(sp_std::marker::PhantomData); - -impl pallet_mmr::primitives::OnNewRoot - for DepositBeefyDigest -where - T: pallet_mmr::Config, - T: pallet_beefy::Config, -{ - fn on_new_root(root: &sp_consensus_beefy_etf::MmrRootHash) { - let digest = sp_runtime::generic::DigestItem::Consensus( - sp_consensus_beefy_etf::BEEFY_ENGINE_ID, - codec::Encode::encode(&sp_consensus_beefy_etf::ConsensusLog::< - ::BeefyId, - >::MmrRoot(*root)), - ); - frame_system::Pallet::::deposit_log(digest); - } -} - -/// Convert BEEFY secp256k1 public keys into Ethereum addresses -pub struct BeefyEcdsaToEthereum; -impl Convert> for BeefyEcdsaToEthereum { - fn convert(beefy_id: sp_consensus_beefy_etf::ecdsa_crypto::AuthorityId) -> Vec { - sp_core::ecdsa::Public::from(beefy_id) - .to_eth_address() - .map(|v| v.to_vec()) - .map_err(|_| { - log::debug!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!"); - }) - .unwrap_or_default() - } -} - -/// Convert BEEFY public keys into Ethereum addresses -/// not really functional at the moment -pub struct BeefyBlsToEthereum; -impl Convert> for BeefyBlsToEthereum { - fn convert(_beefy_id: sp_consensus_beefy_etf::bls_crypto::AuthorityId) -> Vec { - Vec::new() - // sp_core::ecdsa::Public::from(beefy_id) - // .to_eth_address() - // .map(|v| v.to_vec()) - // .map_err(|_| { - // log::debug!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH - // address!"); }) - // .unwrap_or_default() - } -} - -/// The merkle root type -pub type MerkleRootOf = <::Hashing as sp_runtime::traits::Hash>::Output; - -#[frame_support::pallet] -pub mod pallet { - #![allow(missing_docs)] - - use super::*; - use frame_support::pallet_prelude::*; - - /// BEEFY-MMR pallet. - #[pallet::pallet] - pub struct Pallet(_); - - /// The module's configuration trait. - #[pallet::config] - #[pallet::disable_frame_system_supertrait_check] - pub trait Config: pallet_mmr::Config + pallet_beefy::Config { - /// Current leaf version. - /// - /// Specifies the version number added to every leaf that get's appended to the MMR. - /// Read more in [`MmrLeafVersion`] docs about versioning leaves. - type LeafVersion: Get; - - /// Convert BEEFY AuthorityId to a form that would end up in the Merkle Tree. - /// - /// For instance for ECDSA (secp256k1) we want to store uncompressed public keys (65 bytes) - /// and later to Ethereum Addresses (160 bits) to simplify using them on Ethereum chain, - /// but the rest of the Substrate codebase is storing them compressed (33 bytes) for - /// efficiency reasons. - type BeefyAuthorityToMerkleLeaf: Convert<::BeefyId, Vec>; - - /// The type expected for the leaf extra data - type LeafExtra: Member + codec::FullCodec; - - /// Retrieve arbitrary data that should be added to the mmr leaf - type BeefyDataProvider: BeefyDataProvider; - } - - /// Details of current BEEFY authority set. - #[pallet::storage] - pub type BeefyAuthorities = - StorageValue<_, BeefyAuthoritySet>, ValueQuery>; - - /// Details of next BEEFY authority set. - /// - /// This storage entry is used as cache for calls to `update_beefy_next_authority_set`. - #[pallet::storage] - pub type BeefyNextAuthorities = - StorageValue<_, BeefyNextAuthoritySet>, ValueQuery>; -} - -impl LeafDataProvider for Pallet { - type LeafData = MmrLeaf< - BlockNumberFor, - ::Hash, - MerkleRootOf, - T::LeafExtra, - >; - - fn leaf_data() -> Self::LeafData { - MmrLeaf { - version: T::LeafVersion::get(), - parent_number_and_hash: ParentNumberAndHash::::leaf_data(), - leaf_extra: T::BeefyDataProvider::extra_data(), - beefy_next_authority_set: BeefyNextAuthorities::::get(), - } - } -} - -impl sp_consensus_beefy_etf::OnNewValidatorSet<::BeefyId> - for Pallet -where - T: pallet::Config, -{ - /// Compute and cache BEEFY authority sets based on updated BEEFY validator sets. - fn on_new_validator_set( - current_set: &BeefyValidatorSet<::BeefyId>, - next_set: &BeefyValidatorSet<::BeefyId>, - ) { - let current = Pallet::::compute_authority_set(current_set); - let next = Pallet::::compute_authority_set(next_set); - // cache the result - BeefyAuthorities::::put(¤t); - BeefyNextAuthorities::::put(&next); - } -} - -impl Pallet { - /// Return the currently active BEEFY authority set proof. - pub fn authority_set_proof() -> BeefyAuthoritySet> { - BeefyAuthorities::::get() - } - - /// Return the next/queued BEEFY authority set proof. - pub fn next_authority_set_proof() -> BeefyNextAuthoritySet> { - BeefyNextAuthorities::::get() - } - - /// Returns details of a BEEFY authority set. - /// - /// Details contain authority set id, authority set length and a merkle root, - /// constructed from uncompressed secp256k1 public keys converted to Ethereum addresses - /// of the next BEEFY authority set. - fn compute_authority_set( - validator_set: &BeefyValidatorSet<::BeefyId>, - ) -> BeefyAuthoritySet> { - let id = validator_set.id(); - let beefy_addresses = validator_set - .validators() - .into_iter() - .cloned() - .map(T::BeefyAuthorityToMerkleLeaf::convert) - .collect::>(); - let default_eth_addr = [0u8; 20]; - let len = beefy_addresses.len() as u32; - let uninitialized_addresses = beefy_addresses - .iter() - .filter(|&addr| addr.as_slice().eq(&default_eth_addr)) - .count(); - if uninitialized_addresses > 0 { - log::error!( - target: "runtime::beefy", - "Failed to convert {} out of {} BEEFY PublicKeys to ETH addresses!", - uninitialized_addresses, - len, - ); - } - let keyset_commitment = binary_merkle_tree::merkle_root::< - ::Hashing, - _, - >(beefy_addresses) - .into(); - BeefyAuthoritySet { id, len, keyset_commitment } - } -} - -sp_api::decl_runtime_apis! { - /// API useful for BEEFY light clients. - pub trait BeefyMmrApi - where - BeefyAuthoritySet: Decode, - { - /// Return the currently active BEEFY authority set proof. - fn authority_set_proof() -> BeefyAuthoritySet; - - /// Return the next/queued BEEFY authority set proof. - fn next_authority_set_proof() -> BeefyNextAuthoritySet; - } -} diff --git a/pallets/beefy-mmr-etf/src/mock.rs b/pallets/beefy-mmr-etf/src/mock.rs deleted file mode 100644 index 657dbc5..0000000 --- a/pallets/beefy-mmr-etf/src/mock.rs +++ /dev/null @@ -1,202 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use std::vec; - -use codec::Encode; -use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_consensus_beefy_etf::mmr::MmrLeafVersion; -use sp_io::TestExternalities; -use sp_runtime::{ - app_crypto::bls381::Public, - impl_opaque_keys, - traits::{ConvertInto, Keccak256, OpaqueKeys}, - BuildStorage, -}; -use sp_state_machine::BasicExternalities; - -use crate as pallet_beefy_mmr; - -pub use sp_consensus_beefy_etf::{ - bls_crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID, -}; - -impl_opaque_keys! { - pub struct MockSessionKeys { - pub dummy: pallet_beefy::Pallet, - } -} - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Test - { - System: frame_system, - Session: pallet_session, - Mmr: pallet_mmr, - Etf: pallet_etf, - Beefy: pallet_beefy, - BeefyMmr: pallet_beefy_mmr, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; -} - -impl pallet_session::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = u64; - type ValidatorIdOf = ConvertInto; - type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; - type SessionManager = MockSessionManager; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = MockSessionKeys; - type WeightInfo = (); -} - -pub type MmrLeaf = sp_consensus_beefy_etf::mmr::MmrLeaf< - frame_system::pallet_prelude::BlockNumberFor, - ::Hash, - crate::MerkleRootOf, - Vec, ->; - -impl pallet_mmr::Config for Test { - const INDEXING_PREFIX: &'static [u8] = b"mmr"; - - type Hashing = Keccak256; - - type LeafData = BeefyMmr; - - type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - - type WeightInfo = (); -} - -impl pallet_etf::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; -} - -impl pallet_beefy::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; - type MaxNominators = ConstU32<1000>; - type MaxSetIdSessionEntries = ConstU64<100>; - type OnNewValidatorSet = BeefyMmr; - type WeightInfo = (); - type KeyOwnerProof = sp_core::Void; - type EquivocationReportSystem = (); - type RoundCommitmentProvider = Etf; -} - -parameter_types! { - pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(1, 5); -} - -impl pallet_beefy_mmr::Config for Test { - type LeafVersion = LeafVersion; - - type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyBlsToEthereum; - - type LeafExtra = Vec; - - type BeefyDataProvider = DummyDataProvider; -} - -pub struct DummyDataProvider; -impl BeefyDataProvider> for DummyDataProvider { - fn extra_data() -> Vec { - let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; - col.sort(); - binary_merkle_tree::merkle_root::<::Hashing, _>( - col.into_iter().map(|pair| pair.encode()), - ) - .as_ref() - .to_vec() - } -} - -pub struct MockSessionManager; -impl pallet_session::SessionManager for MockSessionManager { - fn end_session(_: sp_staking::SessionIndex) {} - fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { - if idx == 0 || idx == 1 { - Some(vec![1, 2]) - } else if idx == 2 { - Some(vec![3, 4]) - } else { - None - } - } -} - -// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation -// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, -// with the first one containing information to reconstruct the uncompressed key. -pub fn mock_beefy_id(id: u8) -> BeefyId { - let mut buf: [u8; 144] = [id; 144]; - // Set to something valid. - buf[0] = 0x02; - let pk = Public::from_raw(buf); - BeefyId::from(pk) -} - -pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { - vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() -} - -pub fn new_test_ext(ids: Vec) -> TestExternalities { - new_test_ext_raw_authorities(mock_authorities(ids)) -} - -pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let session_keys: Vec<_> = authorities - .iter() - .enumerate() - .map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) - .collect(); - - BasicExternalities::execute_with_storage(&mut t, || { - for (ref id, ..) in &session_keys { - frame_system::Pallet::::inc_providers(id); - } - }); - - let genesis_resharing = authorities.iter().map(|(_idx, id)| (id.clone(), vec![2])).collect(); - - pallet_etf::GenesisConfig:: { genesis_resharing, round_pubkey: vec![1] } - .assimilate_storage(&mut t) - .unwrap(); - - pallet_session::GenesisConfig:: { keys: session_keys } - .assimilate_storage(&mut t) - .unwrap(); - - t.into() -} diff --git a/pallets/beefy-mmr-etf/src/tests.rs b/pallets/beefy-mmr-etf/src/tests.rs deleted file mode 100644 index a367e92..0000000 --- a/pallets/beefy-mmr-etf/src/tests.rs +++ /dev/null @@ -1,239 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use std::vec; - -use codec::{Decode, Encode}; -use sp_consensus_beefy_etf::{ - mmr::{BeefyNextAuthoritySet, MmrLeafVersion}, - ValidatorSet, -}; - -use sp_core::H256; -use sp_io::TestExternalities; -use sp_runtime::{traits::Keccak256, DigestItem}; - -use frame_support::traits::OnInitialize; - -use crate::mock::*; - -fn init_block(block: u64) { - System::set_block_number(block); - Session::on_initialize(block); - Mmr::on_initialize(block); - Beefy::on_initialize(block); - BeefyMmr::on_initialize(block); -} - -pub fn beefy_log(log: ConsensusLog) -> DigestItem { - DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode()) -} - -fn read_mmr_leaf(ext: &mut TestExternalities, key: Vec) -> MmrLeaf { - type Node = pallet_mmr::primitives::DataOrHash; - ext.persist_offchain_overlay(); - let offchain_db = ext.offchain_db(); - offchain_db - .get(&key) - .map(|d| Node::decode(&mut &*d).unwrap()) - .map(|n| match n { - Node::Data(d) => d, - _ => panic!("Unexpected MMR node."), - }) - .unwrap() -} - -#[test] -fn should_contain_mmr_digest() { - let mut ext = new_test_ext(vec![1, 2, 3, 4]); - ext.execute_with(|| { - init_block(1); - - assert_eq!( - System::digest().logs, - vec![ - beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new( - vec![mock_beefy_id(1), mock_beefy_id(2)], - vec![ - mock_beefy_id(1), - mock_beefy_id(2), - mock_beefy_id(3), - mock_beefy_id(4) - ], - 1 - ) - .unwrap() - )), - beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" - ))) - ] - ); - - // unique every time - init_block(2); - - assert_eq!( - System::digest().logs, - vec![ - beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new( - vec![mock_beefy_id(1), mock_beefy_id(2)], - vec![ - mock_beefy_id(1), - mock_beefy_id(2), - mock_beefy_id(3), - mock_beefy_id(4) - ], - 1 - ) - .unwrap() - )), - beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" - ))), - beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new( - vec![mock_beefy_id(3), mock_beefy_id(4)], - vec![ - mock_beefy_id(1), - mock_beefy_id(2), - mock_beefy_id(3), - mock_beefy_id(4) - ], - 2 - ) - .unwrap() - )), - beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2" - ))), - ] - ); - }); -} - -#[test] -fn should_contain_valid_leaf_data() { - fn node_offchain_key(pos: usize, parent_hash: H256) -> Vec { - (::INDEXING_PREFIX, pos as u64, parent_hash).encode() - } - - let mut ext = new_test_ext(vec![1, 2, 3, 4]); - let parent_hash = ext.execute_with(|| { - init_block(1); - frame_system::Pallet::::parent_hash() - }); - - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(0, parent_hash)); - assert_eq!( - mmr_leaf, - MmrLeaf { - version: MmrLeafVersion::new(1, 5), - parent_number_and_hash: (0_u64, H256::repeat_byte(0x45)), - beefy_next_authority_set: BeefyNextAuthoritySet { - id: 2, - len: 2, - keyset_commitment: array_bytes::hex_n_into_unchecked( - "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" - ) - }, - leaf_extra: array_bytes::hex2bytes_unchecked( - "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" - ) - } - ); - - // build second block on top - let parent_hash = ext.execute_with(|| { - init_block(2); - frame_system::Pallet::::parent_hash() - }); - - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(1, parent_hash)); - assert_eq!( - mmr_leaf, - MmrLeaf { - version: MmrLeafVersion::new(1, 5), - parent_number_and_hash: (1_u64, H256::repeat_byte(0x45)), - beefy_next_authority_set: BeefyNextAuthoritySet { - id: 3, - len: 2, - keyset_commitment: array_bytes::hex_n_into_unchecked( - "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" - ) - }, - leaf_extra: array_bytes::hex2bytes_unchecked( - "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" - ) - } - ); -} - -#[test] -fn should_update_authorities() { - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let auth_set = BeefyMmr::authority_set_proof(); - let next_auth_set = BeefyMmr::next_authority_set_proof(); - - // check current authority set - assert_eq!(0, auth_set.id); - assert_eq!(2, auth_set.len); - let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>( - "176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96", - ); - assert_eq!(want, auth_set.keyset_commitment); - - // next authority set should have same validators but different id - assert_eq!(1, next_auth_set.id); - assert_eq!(auth_set.len, next_auth_set.len); - assert_eq!(auth_set.keyset_commitment, next_auth_set.keyset_commitment); - - let announced_set = next_auth_set; - init_block(1); - let auth_set = BeefyMmr::authority_set_proof(); - let next_auth_set = BeefyMmr::next_authority_set_proof(); - - // check new auth are expected ones - assert_eq!(announced_set, auth_set); - assert_eq!(1, auth_set.id); - // check next auth set - assert_eq!(2, next_auth_set.id); - let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>( - "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", - ); - assert_eq!(2, next_auth_set.len); - assert_eq!(want, next_auth_set.keyset_commitment); - - let announced_set = next_auth_set; - init_block(2); - let auth_set = BeefyMmr::authority_set_proof(); - let next_auth_set = BeefyMmr::next_authority_set_proof(); - - // check new auth are expected ones - assert_eq!(announced_set, auth_set); - assert_eq!(2, auth_set.id); - // check next auth set - assert_eq!(3, next_auth_set.id); - let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>( - "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", - ); - assert_eq!(2, next_auth_set.len); - assert_eq!(want, next_auth_set.keyset_commitment); - }); -} diff --git a/pallets/etf/Cargo.toml b/pallets/etf/Cargo.toml index c941909..388d7fb 100644 --- a/pallets/etf/Cargo.toml +++ b/pallets/etf/Cargo.toml @@ -42,8 +42,6 @@ sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "te sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-beefy = { package = "pallet-beefy-etf", path = "../beefy-etf" } -pallet-beefy-mmr = { package = "pallet-beefy-mmr-etf", path = "../beefy-mmr-etf" } pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } array-bytes = "6.1" binary-merkle-tree = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } diff --git a/pallets/murmur/Cargo.toml b/pallets/murmur/Cargo.toml deleted file mode 100644 index 3b20b9f..0000000 --- a/pallets/murmur/Cargo.toml +++ /dev/null @@ -1,108 +0,0 @@ -[package] -name = "pallet-murmur" -version = "0.1.0-dev" -description = "FRAME pallet to create and execute murmur wallets" -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -array-bytes = "4.1" -log = { version = "0.4.17", default-features = false } -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ - "derive", -] } -serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false } -ark-serialize = { version = "0.4.0", features = [ "derive" ], default-features = false } -ark-bls12-381 = { version = "0.4.0", features = ["curve"], default-features = false } -primitive-types = { version = "0.12.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -frame-benchmarking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false , optional = true } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -ckb-merkle-mountain-range = { version = "0.5.2", default-features = false } -sha3 = { version = "0.10.8", default-features = false } -murmur-core = { package = "murmur-core", git = "https://github.com/ideal-lab5/murmur.git", default-features = false } -w3f-bls = { version = "0.1.3", default-features = false } - -# local dependencies -pallet-proxy = { default-features = false, path = "../proxy" } -pallet-randomness-beacon = { default-features = false, path = "../randomness-beacon"} - -[dev-dependencies] -ark-transcript = { git = "https://github.com/w3f/ring-vrf.git", default-features = false } -frame-support-test = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-balances = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-timestamp = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-etf = { path = "../etf", default-features = false } -pallet-beefy-etf = { path = "../beefy-etf", default-features = false } -pallet-beefy-mmr-etf = { path = "../beefy-mmr-etf", default-features = false } -sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } -sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -rand_chacha ="0.3.1" -rand_core = { version = "0.6.4", features = ["getrandom"], default-features = false } -ark-std = { version = "0.4.0", default-features = false } -hex = "0.4.3" -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -etf-crypto-primitives = { default-features = false, git = "https://github.com/ideal-lab5/etf-sdk.git"} -binary-merkle-tree = { version = "15.0.0", default-features = false } -murmur-test-utils = { package = "murmur-test-utils", git = "https://github.com/ideal-lab5/murmur.git", default-features = false } -env_logger = "*" - -[features] -default = ["std"] -std = [ - "serde/std", - "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "primitive-types/std", - "sp-std/std", - "sp-runtime/std", - "sp-io/std", - "sp-core/std", - "ark-transcript/std", - "ark-serialize/std", - "ark-bls12-381/std", - "pallet-balances/std", - "pallet-proxy/std", - "pallet-randomness-beacon/std", - "ckb-merkle-mountain-range/std", - "sha3/std", - "murmur-core/std", - "etf-crypto-primitives/std", - "w3f-bls/std", - "pallet-beefy-etf/std", - "pallet-beefy-mmr-etf/std", - "pallet-etf/std", - "pallet-session/std", - "pallet-mmr/std", - "sp-staking/std", - "binary-merkle-tree/std", - "sp-state-machine/std", - "murmur-test-utils/std", - "rand_core/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", -] -try-runtime = [ - "frame-support/try-runtime", - "pallet-balances/try-runtime" -] diff --git a/pallets/murmur/README.md b/pallets/murmur/README.md deleted file mode 100644 index 04d31dd..0000000 --- a/pallets/murmur/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Murmur Pallet - -The Murmur Pallet is a FRAME pallet designed to create and execute Murmur wallets. It provides functionalities to create time-based proxy accounts and proxy calls after verifying ciphertexts using Merkle proofs. - -## Overview - -The Murmur Pallet allows users to create proxy accounts with unique names and execute proxy calls securely. It leverages Merkle Mountain Range (MMR) for proof verification and integrates with the `pallet_proxy` for proxy call execution. - -## Features - -- **Create Proxy Accounts**: Create time-based proxy accounts with unique names. -- **Proxy Calls**: Proxy calls after verifying the ciphertext and Merkle proof. - -## Usage - -### Create a Proxy Account - -To create a proxy account, use the `create` dispatchable function: - -```rust -pub fn create( - origin: OriginFor, - root: Vec, - size: u64, - name: BoundedVec>, -) -> DispatchResult -``` - -### Proxy a Call - -To proxy a call, use the `proxy` dispatchable function: - -```rust -pub fn proxy( - _origin: OriginFor, - name: BoundedVec>, - position: u64, - hash: Vec, - ciphertext: Vec, - proof: Vec>, - size: u64, - call: sp_std::boxed::Box<::RuntimeCall>, -) -> DispatchResult -``` - -## Events - -The pallet emits the following events: - -- `OtpProxyCreated`: Emitted when a new proxy account is created. -- `OtpProxyExecuted`: Emitted when a proxy call is executed. - -## Errors - -The pallet can return the following errors: - -- `BadCiphertext`: The provided ciphertext is invalid. -- `DuplicateName`: The provided name is already in use. -- `InvalidOTP`: The provided OTP is invalid. -- `InvalidMerkleProof`: The provided Merkle proof is invalid. -- `InvalidProxy`: The proxy account is invalid. -- `ProxyDNE`: The proxy account does not exist. - -## Build - -To build the project, use the following command: - -```shell -cargo build -``` - -## Testing - -To run the tests, use the following command: - -```shell -cargo test -``` - -## Contributing - -Contributions are welcome! Please open an issue or submit a pull request. - -## License - -This project is licensed under the Apache-2.0. See the [LICENSE](../../LICENSE) file for details. - -## Contact - -For any inquiries, please contact [Ideal Labs](https://idealabs.network). diff --git a/pallets/murmur/src/lib.rs b/pallets/murmur/src/lib.rs deleted file mode 100644 index 47d38bb..0000000 --- a/pallets/murmur/src/lib.rs +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -#![cfg_attr(not(feature = "std"), no_std)] - -//! # Murmur Pallet -pub use pallet::*; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -use ckb_merkle_mountain_range::MerkleProof; -use codec::{Decode, Encode}; -use frame_support::{ - dispatch::GetDispatchInfo, - pallet_prelude::*, - traits::{ConstU32, IsSubType}, -}; -use murmur_core::{ - murmur::verifier::{verify_execute, verify_update}, - types::{Leaf, MergeLeaves}, -}; -use pallet_randomness_beacon::TimelockEncryptionProvider; -use scale_info::TypeInfo; -use sp_runtime::traits::Dispatchable; -use sp_std::{vec, vec::Vec}; -use w3f_bls::TinyBLS377; - -/// A bounded name of a Murmur Proxy -pub type Name = BoundedVec>; -/// A root of an MMR -pub type Root = BoundedVec>; -/// A serialized public key (TinyBLS377 > SignatureGroup) -pub type SerializedPublicKey = BoundedVec>; -/// A serialized DLEQ proof -pub type Proof = BoundedVec>; - -/// A struct to represent specific details of a murmur proxy account -#[derive( - Debug, - PartialEq, - Eq, - Hash, - Clone, - Encode, - Decode, - TypeInfo, - serde::Serialize, - serde::Deserialize, -)] -pub struct MurmurProxyDetails { - /// The proxy account address - pub address: AccountId, - /// The MMR root - pub root: Vec, - /// The MMR size - pub size: u64, - /// The serialized VRF pubkey - pub pubkey: Vec, - /// The nonce of the Murmur proxy - pub nonce: u64, -} - -#[frame_support::pallet(dev_mode)] -pub mod pallet { - use super::*; - use frame_system::pallet_prelude::*; - use sp_runtime::{traits::Zero, DispatchResult}; - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(_); - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config + pallet_proxy::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The overarching call type. - type RuntimeCall: Parameter - + Dispatchable - + GetDispatchInfo - + From> - + IsSubType> - + IsType<::RuntimeCall>; - /// Something that can decrypt messages locked for the current slot - type TlockProvider: TimelockEncryptionProvider>; - } - - /// A registry to track registered 'usernames' for OTP wallets - // Q: what happens when this map becomes very large? in terms of query time? - #[pallet::storage] - pub(super) type Registry = - StorageMap<_, Blake2_256, Name, MurmurProxyDetails, OptionQuery>; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A murmur proxy was created - MurmurProxyCreated, - /// A murmur proxy was execute - MurmurProxyExecuted, - /// A murmur proxy was updated - MurmurProxyUpdated, - } - - // Errors inform users that something went wrong. - #[pallet::error] - pub enum Error { - /// The ciphertext could not be recovered - BadCiphertext, - /// The input name is already used - DuplicateName, - /// The OTP code is invalid - InvalidOTP, - /// The Merkle proof could not be verified - InvalidMerkleProof, - /// The Schnorr proof could not be verified - SchnorrProofVerificationFailed, - /// https://crypto.stanford.edu/cs355/19sp/lec5.pdf - InvalidSchnorrProof, - /// The proxy is not registered as a Murmur wallet or does not exist - InvalidProxy, - } - - #[pallet::call] - impl Pallet { - /// Create a time-based proxy account - /// * `name`: The name to assign to the murmur proxy - /// * `root`: The MMR root - /// * `size`: The size (number of leaves) of the MMR - /// * `proof`: A (serialized) DLEQ proof - /// * `public_key`: A (serialized) public key associated with the DLEQ - #[pallet::weight(0)] - #[pallet::call_index(0)] - pub fn create( - origin: OriginFor, - name: Name, - root: Root, - size: u64, - proof: Proof, - pubkey: SerializedPublicKey, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - let nonce = 0; - - let validity = verify_update::(proof.to_vec(), pubkey.to_vec(), nonce) - .map_err(|_| Error::::SchnorrProofVerificationFailed)?; - - ensure!(validity == true, Error::::InvalidSchnorrProof); - - // ensure unique names - ensure!(Registry::::get(name.clone()).is_none(), Error::::DuplicateName); - - // create a pure proxy with no delegate - let signed_origin: T::RuntimeOrigin = - frame_system::RawOrigin::Signed(who.clone()).into(); - pallet_proxy::Pallet::::create_pure( - signed_origin, - T::ProxyType::default(), - BlockNumberFor::::zero(), - 0u16, - true, - )?; - - let address = - pallet_proxy::Pallet::::pure_account(&who, &T::ProxyType::default(), 0, None); - - Registry::::insert( - name, - &MurmurProxyDetails { - address, - root: root.to_vec(), - size, - pubkey: pubkey.to_vec(), - nonce, - }, - ); - Self::deposit_event(Event::MurmurProxyCreated); - - Ok(()) - } - - /// Update the MMR associated with a Murmur proxy - /// Does not require a signed origin - /// - /// * `name`: The name to assign to the murmur proxy - /// * `root`: The MMR root - /// * `size`: The size (number of leaves) of the MMR - /// * `proof`: A (serialized) DLEQ proof - #[pallet::weight(0)] - #[pallet::call_index(1)] - pub fn update( - _origin: OriginFor, - name: Name, - new_root: Root, - new_size: u64, - proof: Proof, - ) -> DispatchResult { - let proxy_details = Registry::::get(name.clone()).ok_or(Error::::InvalidProxy)?; - // verify the proof - let next_nonce = proxy_details.nonce + 1; - let validity = verify_update::( - proof.to_vec(), - proxy_details.pubkey.to_vec(), - next_nonce, - ) - .map_err(|_| Error::::SchnorrProofVerificationFailed)?; - - ensure!(validity, Error::::InvalidSchnorrProof); - // update proxy details - let mut new_proxy_details = proxy_details.clone(); - new_proxy_details.root = new_root.to_vec(); - new_proxy_details.size = new_size; - new_proxy_details.nonce = next_nonce; - - Registry::::insert(name, &new_proxy_details); - Self::deposit_event(Event::MurmurProxyUpdated); - - Ok(()) - } - - /// Proxy a call after verifying the ciphertext - /// this function first checks the validity of the merkle proof (using the ciphertext) - /// if valid, it decrypts the ciphertext and uses it to verify the hash - /// if valid, it proxies the call - /// - /// * `name`: The uid of the murmur proxy - /// * `position`: The position in the MMR of the encrypted OTP code - /// * `hash`: A hash to commit to the OTP code and call data - /// * `ciphertext`: The encrypted OTP code - /// * `proof`: A merkle proof that the target leaf is in the expected MMR at the given - /// position - /// * `size`: The size of the Merkle proof - /// * `call`: The call to be proxied - #[pallet::weight(0)] - #[pallet::call_index(2)] - pub fn proxy( - _origin: OriginFor, - name: BoundedVec>, - position: u64, - hash: Vec, - ciphertext: Vec, - proof: Vec>, - size: u64, - call: sp_std::boxed::Box<::RuntimeCall>, - ) -> DispatchResult { - let when = T::TlockProvider::latest(); - - let proxy_details = Registry::::get(name.clone()).ok_or(Error::::InvalidProxy)?; - - let result = T::TlockProvider::decrypt_at(&ciphertext, when) - .map_err(|_| Error::::BadCiphertext)?; - - let otp = result.message; - let leaves: Vec = proof.clone().into_iter().map(|p| Leaf(p)).collect::>(); - - let merkle_proof = MerkleProof::::new(size, leaves.clone()); - - let root = Leaf(proxy_details.root.to_vec()); - - let validity = verify_execute( - root, - merkle_proof, - hash, - ciphertext, - &otp, - &call.encode(), - position, - ); - - frame_support::ensure!(validity, Error::::InvalidMerkleProof); - - let def = pallet_proxy::Pallet::::find_proxy( - &proxy_details.address, - None, - Some(T::ProxyType::default()), - ) - .map_err(|_| Error::::InvalidProxy)?; - - pallet_proxy::Pallet::::do_proxy(def, proxy_details.address, *call); - - Self::deposit_event(Event::MurmurProxyExecuted); - Ok(()) - } - } -} diff --git a/pallets/murmur/src/mock.rs b/pallets/murmur/src/mock.rs deleted file mode 100644 index 76e24c2..0000000 --- a/pallets/murmur/src/mock.rs +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -use super::*; -use std::vec; - -use crate as pallet_murmur; -use ark_serialize::CanonicalDeserialize; -use ark_transcript::{digest::Update, Transcript}; -use codec::Encode; -use etf_crypto_primitives::encryption::tlock::{DecryptionResult, TLECiphertext}; -use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ConstU128, ConstU32, ConstU64, InstanceFilter}, -}; -use rand_chacha::ChaCha20Rng; -use rand_core::SeedableRng; -use sha3::Digest; -use sp_consensus_beefy_etf::{mmr::MmrLeafVersion, test_utils::etf_genesis}; -use sp_core::Pair; -use sp_io::TestExternalities; -use sp_runtime::{ - impl_opaque_keys, - testing::TestXt, - traits::{BlakeTwo256, ConvertInto, Keccak256, OpaqueKeys}, - BuildStorage, -}; -use sp_state_machine::BasicExternalities; -use w3f_bls::TinyBLS377; - -pub use sp_consensus_beefy_etf::bls_crypto::AuthorityId as BeefyId; - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Proxy: pallet_proxy, - Murmur: pallet_murmur, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -impl frame_system::offchain::SendTransactionTypes for Test -where - RuntimeCall: From, -{ - type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; -} - -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = u128; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU128<1>; - type AccountStore = System; - type WeightInfo = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); - type FreezeIdentifier = (); - type MaxFreezes = (); -} - -pub struct DummyTlockProvider; -impl TimelockEncryptionProvider for DummyTlockProvider { - fn decrypt_at( - bytes: &[u8], - when: u64, - ) -> Result { - let seed = vec![1, 2, 3]; - - let mut transcript = Transcript::new_labeled(murmur_core::murmur::MURMUR_PROTO_OTP); - transcript.write_bytes(&seed); - let nonce: u64 = 0; - transcript.write_bytes(&nonce.to_be_bytes()); - - let ephemeral_msk: Vec = vec![ - 10, 124, 150, 208, 196, 211, 212, 13, 177, 116, 154, 11, 235, 242, 139, 2, 187, 80, 52, - 58, 125, 72, 184, 194, 165, 119, 212, 134, 171, 185, 191, 101, - ]; - - let ciphertext: TLECiphertext = - TLECiphertext::deserialize_compressed(&mut &bytes[..]).unwrap(); - - let otp = ciphertext.aes_decrypt(ephemeral_msk.as_slice().to_vec()).unwrap(); - - Ok(DecryptionResult { message: otp.message, secret: [2; 32] }) - } - - fn latest() -> u64 { - 10 - } -} - -impl pallet_murmur::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type TlockProvider = DummyTlockProvider; -} - -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - Any, - JustTransfer, -} -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::JustTransfer => { - matches!( - c, - RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) - ) - }, - } - } - fn is_superset(&self, o: &Self) -> bool { - self == &ProxyType::Any || self == o - } -} - -impl pallet_proxy::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - type ProxyDepositBase = ConstU128<1>; - type ProxyDepositFactor = ConstU128<1>; - type MaxProxies = ConstU32<4>; - type WeightInfo = (); - type CallHasher = BlakeTwo256; - type MaxPending = ConstU32<2>; - type AnnouncementDepositBase = ConstU128<1>; - type AnnouncementDepositFactor = ConstU128<1>; -} - -// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation -// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, -// with the first one containing information to reconstruct the uncompressed key. -pub fn mock_beefy_id(id: u8) -> BeefyId { - // generate a new keypair and get the public key - let kp = sp_core::bls::Pair::from_seed_slice(&[id; 32]).unwrap(); - BeefyId::from(kp.public()) -} - -pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { - vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() -} - -pub fn new_test_ext(ids: Vec) -> TestExternalities { - new_test_ext_raw_authorities(mock_authorities(ids)) -} - -pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let balances: Vec<_> = (0..authorities.len()).map(|i| (i as u64, 10_000_000)).collect(); - - pallet_balances::GenesisConfig:: { balances } - .assimilate_storage(&mut t) - .unwrap(); - - t.into() -} diff --git a/pallets/murmur/src/tests.rs b/pallets/murmur/src/tests.rs deleted file mode 100644 index b26e226..0000000 --- a/pallets/murmur/src/tests.rs +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -use crate::{self as murmur, mock::*, Error}; -use codec::Encode; -use frame_support::{assert_noop, assert_ok, traits::ConstU32, BoundedVec}; -use frame_system::Call as SystemCall; -use log::info; -use murmur_core::{ - murmur::EngineTinyBLS377, - types::{BlockNumber, Identity, IdentityBuilder}, -}; -use murmur_test_utils::{get_dummy_beacon_pubkey, MurmurStore}; -use rand_chacha::ChaCha20Rng; -use rand_core::SeedableRng; -use sp_consensus_beefy_etf::{known_payloads, Commitment, Payload}; -use sp_core::{bls377, Pair}; -use w3f_bls::{DoublePublicKey, SerializableToBytes, TinyBLS377}; - -#[derive(Debug)] -pub struct BasicIdBuilder; -impl IdentityBuilder for BasicIdBuilder { - fn build_identity(at: BlockNumber) -> Identity { - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let commitment = Commitment { - payload, - block_number: at, - validator_set_id: 0, /* TODO: how to ensure correct validator set ID is used? could - * just always set to 1 for now, else set input param. */ - }; - Identity::new(&commitment.encode()) - } -} - -/* -Test Contants -*/ -pub const BLOCK_SCHEDULE: &[BlockNumber] = - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; -pub const WHEN: u64 = 10; -pub const SEED: &[u8] = &[1, 2, 3]; - -fn calculate_signature( - id: u8, - serialized_resharing: &[u8], - message: &[u8], -) -> (bls377::Public, bls377::Signature) { - let kp = sp_core::bls::Pair::from_seed_slice(&[id; 32]).unwrap(); - let etf_kp = kp.acss_recover(serialized_resharing, 1).unwrap(); - (etf_kp.public(), etf_kp.sign(message)) -} - -#[test] -fn it_can_create_new_proxy_with_unique_name() { - let seed = b"seed".to_vec(); - let unique_name = b"name".to_vec(); - let bounded_name = BoundedVec::>::truncate_from(unique_name); - let block_schedule = vec![1, 2, 3]; - - let size = 3; - - new_test_ext(vec![0]).execute_with(|| { - let round_pubkey_bytes = get_dummy_beacon_pubkey(); - let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes).unwrap(); - - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let mmr_store = MurmurStore::::new::( - seed.clone().into(), - block_schedule.clone(), - 0, - round_pubkey, - &mut rng, - ) - .unwrap(); - - let root = mmr_store.root.clone(); - - let bounded_root = BoundedVec::>::truncate_from(root.0); - let bounded_pubkey = BoundedVec::>::truncate_from(mmr_store.public_key); - let bounded_proof = BoundedVec::>::truncate_from(mmr_store.proof); - - assert_ok!(Murmur::create( - RuntimeOrigin::signed(0), - bounded_name.clone(), - bounded_root, - size, - bounded_proof.clone(), - bounded_pubkey.clone(), - )); - - // check storage - let registered_proxy = murmur::Registry::::get(bounded_name.clone()); - assert!(registered_proxy.is_some()); - }); -} - -#[test] -fn it_fails_to_create_new_proxy_with_duplicate_name() { - let seed = b"seed".to_vec(); - let unique_name = b"name".to_vec(); - let bounded_name = BoundedVec::>::truncate_from(unique_name); - let block_schedule = vec![1, 2, 3]; - - let size = 3; - - new_test_ext(vec![0]).execute_with(|| { - let round_pubkey_bytes = get_dummy_beacon_pubkey(); - let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes).unwrap(); - - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let mmr_store = MurmurStore::::new::( - seed.clone().into(), - block_schedule.clone(), - 0, - round_pubkey, - &mut rng, - ) - .unwrap(); - - let root = mmr_store.root.clone(); - let bounded_root = BoundedVec::>::truncate_from(root.0); - let bounded_pubkey = BoundedVec::>::truncate_from(mmr_store.public_key); - let bounded_proof = BoundedVec::>::truncate_from(mmr_store.proof); - - assert_ok!(Murmur::create( - RuntimeOrigin::signed(0), - bounded_name.clone(), - bounded_root.clone(), - size, - bounded_proof.clone(), - bounded_pubkey.clone(), - )); - - // check storage - let registered_proxy = murmur::Registry::::get(bounded_name.clone()); - assert!(registered_proxy.is_some()); - - assert_noop!( - Murmur::create( - RuntimeOrigin::signed(0), - bounded_name.clone(), - bounded_root, - size, - bounded_proof.clone(), - bounded_pubkey.clone(), - ), - Error::::DuplicateName - ); - - // verify that the proxy exists - }); -} - -#[test] -fn it_can_update_proxy() { - let _ = env_logger::try_init(); - let unique_name = b"name".to_vec(); - let bounded_name = BoundedVec::>::truncate_from(unique_name); - - new_test_ext(vec![0]).execute_with(|| { - let round_pubkey_bytes = get_dummy_beacon_pubkey(); - - let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes).unwrap(); - let same_round_pubkey = - DoublePublicKey::::from_bytes(&round_pubkey_bytes).unwrap(); - - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let mmr_store = MurmurStore::::new::( - SEED.to_vec(), - BLOCK_SCHEDULE.to_vec(), - 0, - round_pubkey, - &mut rng, - ) - .unwrap(); - - let proof = mmr_store.proof.clone(); - let pk = mmr_store.public_key.clone(); - - // use a new rng to ensure non-deterministic output - let mut new_rng = ChaCha20Rng::seed_from_u64(1); - let another_murmur_store = - MurmurStore::::new::( - SEED.to_vec(), - BLOCK_SCHEDULE.to_vec(), - 1, - same_round_pubkey, - &mut new_rng, - ) - .unwrap(); - - let another_proof = another_murmur_store.proof; - - // now we create a proxy and then update it - /* CREATE THE PROXY */ - let root = mmr_store.root.clone(); - let bounded_root = BoundedVec::>::truncate_from(root.0); - let bounded_pubkey = BoundedVec::>::truncate_from(pk.clone()); - let bounded_proof = BoundedVec::>::truncate_from(proof.clone()); - - assert_ok!(Murmur::create( - RuntimeOrigin::signed(0), - bounded_name.clone(), - bounded_root, - BLOCK_SCHEDULE.len() as u64, - bounded_proof.clone(), - bounded_pubkey.clone(), - )); - - // check storage - let registered_proxy = murmur::Registry::::get(bounded_name.clone()); - assert!(registered_proxy.is_some()); - - /* UPDATE THE PROXY */ - let second_root = another_murmur_store.root.clone(); - let second_bounded_root = BoundedVec::>::truncate_from(second_root.0); - let second_bounded_proof = - BoundedVec::>::truncate_from(another_proof.clone()); - - assert_ok!(Murmur::update( - RuntimeOrigin::signed(0), - bounded_name.clone(), - second_bounded_root, - BLOCK_SCHEDULE.len() as u64, - second_bounded_proof.clone(), - )); - }); -} - -#[test] -fn it_can_proxy_valid_calls() { - let unique_name = b"name".to_vec(); - let bounded_name = BoundedVec::>::truncate_from(unique_name); - let size = BLOCK_SCHEDULE.len() as u64; - - new_test_ext(vec![0]).execute_with(|| { - let round_pubkey_bytes = get_dummy_beacon_pubkey(); - let round_pubkey = DoublePublicKey::::from_bytes(&round_pubkey_bytes).unwrap(); - - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let mmr_store = MurmurStore::::new::( - SEED.to_vec(), - BLOCK_SCHEDULE.to_vec().clone(), - 0, - round_pubkey, - &mut rng, - ) - .unwrap(); - - let root = mmr_store.root.clone(); - let bounded_root = BoundedVec::>::truncate_from(root.0); - let bounded_pubkey = - BoundedVec::>::truncate_from(mmr_store.public_key.clone()); - let bounded_proof = BoundedVec::>::truncate_from(mmr_store.proof.clone()); - - assert_ok!(Murmur::create( - RuntimeOrigin::signed(0), - bounded_name.clone(), - bounded_root.clone(), - size, - bounded_proof.clone(), - bounded_pubkey.clone(), - )); - - // we must simulate the protocol here - // in practice, the rng would be seeded from user input - // along with some secure source of entropy - let call = call_remark(vec![1, 2, 3, 4, 5]); - let (merkle_proof, commitment, ciphertext, pos) = - mmr_store.execute(SEED.to_vec().clone(), 10, call.encode().to_vec()).unwrap(); - - let proof_items: Vec> = merkle_proof - .proof_items() - .iter() - .map(|leaf| leaf.0.to_vec()) - .collect::>(); - - assert_ok!(Murmur::proxy( - RuntimeOrigin::signed(0), - bounded_name.clone(), - pos, - commitment, - ciphertext, - proof_items, - merkle_proof.mmr_size(), - Box::new(call), - )); - }); -} - -fn call_remark(value: Vec) -> RuntimeCall { - RuntimeCall::System(SystemCall::remark { remark: value }) -} diff --git a/pallets/proxy/Cargo.toml b/pallets/proxy/Cargo.toml deleted file mode 100644 index cfc97f5..0000000 --- a/pallets/proxy/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "pallet-proxy" -version = "0.1.0-dev" -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -description = "FRAME proxying pallet" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -[dev-dependencies] -pallet-balances = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-utility = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", - "pallet-balances/std", - "pallet-utility/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-balances/try-runtime", - "pallet-utility/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/proxy/README.md b/pallets/proxy/README.md deleted file mode 100644 index 02ac0c9..0000000 --- a/pallets/proxy/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Proxy Pallet - -This is a FRAME pallet that allows accounts to delegate permission to other accounts to dispatch specific types of calls from their signed origin. This delegation can include requirements for the delegate to announce their intended actions before execution, giving the original account the opportunity to veto the action. - -## Overview - -The Proxy Module provides a flexible mechanism for account delegation, enabling various use cases such as account recovery, multi-signature wallets, and more. It supports time-based announcements and vetoes, ensuring that the original account retains control over critical actions. - -## Features - -- **Account Delegation**: Delegate permission to other accounts to perform specific actions. -- **Announcement and Veto**: Require delegates to announce actions before execution, allowing the original account to veto if necessary. - -## Events - -The module emits the following events: - -- `ProxyAdded`: Emitted when a new proxy is added. -- `Announced`: Emitted when a proxy call is announced. -- `ProxyExecuted`: Emitted when a proxy call is executed. -- `PureCreated`: Emitted when a new pure proxy is created. -- `ProxyRemoved`: Emitted when a proxy is removed. - -## Errors - -The module can return the following errors: - -- `TooMany`: The account has too many proxies. -- `NotFound`: The proxy was not found. -- `NotProxy`: The account is not a proxy. -- `Unproxyable`: The call is not allowed to be proxied. -- `Duplicate`: The proxy is already in use. -- `NoPermission`: The account does not have permission to proxy the call. -- `Unannounced`: The call was not announced. -- `NoSelfProxy`: An account cannot proxy to itself. - -## Build - -To build the project, use the following command: - -```shell -cargo build -``` - -## Testing - -To run the tests, use the following command: - -```shell -cargo test -``` - -## Contributing - -Contributions are welcome! Please open an issue or submit a pull request. - -## License - -This project is licensed under the Apache-2.0. See the [LICENSE](../../LICENSE) file for details. - -## Contact - -For any inquiries, please contact [Ideal Labs](https://idealabs.network). diff --git a/pallets/proxy/src/benchmarking.rs b/pallets/proxy/src/benchmarking.rs deleted file mode 100644 index 5059f92..0000000 --- a/pallets/proxy/src/benchmarking.rs +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -// Benchmarks for Proxy Pallet - -#![cfg(feature = "runtime-benchmarks")] - -use super::*; -use crate::Pallet as Proxy; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_runtime::traits::Bounded; - -const SEED: u32 = 0; - -fn assert_last_event(generic_event: ::RuntimeEvent) { - frame_system::Pallet::::assert_last_event(generic_event.into()); -} - -fn add_proxies(n: u32, maybe_who: Option) -> Result<(), &'static str> { - let caller = maybe_who.unwrap_or_else(whitelisted_caller); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - for i in 0..n { - let real = T::Lookup::unlookup(account("target", i, SEED)); - - Proxy::::add_proxy( - RawOrigin::Signed(caller.clone()).into(), - real, - T::ProxyType::default(), - BlockNumberFor::::zero(), - )?; - } - Ok(()) -} - -fn add_announcements( - n: u32, - maybe_who: Option, - maybe_real: Option, -) -> Result<(), &'static str> { - let caller = maybe_who.unwrap_or_else(|| account("caller", 0, SEED)); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - let real = if let Some(real) = maybe_real { - real - } else { - let real = account("real", 0, SEED); - T::Currency::make_free_balance_be(&real, BalanceOf::::max_value() / 2u32.into()); - Proxy::::add_proxy( - RawOrigin::Signed(real.clone()).into(), - caller_lookup, - T::ProxyType::default(), - BlockNumberFor::::zero(), - )?; - real - }; - let real_lookup = T::Lookup::unlookup(real); - for _ in 0..n { - Proxy::::announce( - RawOrigin::Signed(caller.clone()).into(), - real_lookup.clone(), - T::CallHasher::hash_of(&("add_announcement", n)), - )?; - } - Ok(()) -} - -benchmarks! { - proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - // In this case the caller is the "target" proxy - let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - // ... and "real" is the traditional caller. This is not a typo. - let real: T::AccountId = whitelisted_caller(); - let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) - } - - proxy_announced { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - // In this case the caller is the "target" proxy - let caller: T::AccountId = account("pure", 0, SEED); - let delegate: T::AccountId = account("target", p - 1, SEED); - let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value() / 2u32.into()); - // ... and "real" is the traditional caller. This is not a typo. - let real: T::AccountId = whitelisted_caller(); - let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - Proxy::::announce( - RawOrigin::Signed(delegate.clone()).into(), - real_lookup.clone(), - T::CallHasher::hash_of(&call), - )?; - add_announcements::(a, Some(delegate.clone()), None)?; - }: _(RawOrigin::Signed(caller), delegate_lookup, real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) - } - - remove_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - // In this case the caller is the "target" proxy - let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - // ... and "real" is the traditional caller. This is not a typo. - let real: T::AccountId = whitelisted_caller(); - let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - Proxy::::announce( - RawOrigin::Signed(caller.clone()).into(), - real_lookup.clone(), - T::CallHasher::hash_of(&call), - )?; - add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)) - verify { - let (announcements, _) = Announcements::::get(&caller); - assert_eq!(announcements.len() as u32, a); - } - - reject_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - // In this case the caller is the "target" proxy - let caller: T::AccountId = account("target", p - 1, SEED); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - // ... and "real" is the traditional caller. This is not a typo. - let real: T::AccountId = whitelisted_caller(); - let real_lookup = T::Lookup::unlookup(real.clone()); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - Proxy::::announce( - RawOrigin::Signed(caller.clone()).into(), - real_lookup, - T::CallHasher::hash_of(&call), - )?; - add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)) - verify { - let (announcements, _) = Announcements::::get(&caller); - assert_eq!(announcements.len() as u32, a); - } - - announce { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - // In this case the caller is the "target" proxy - let caller: T::AccountId = account("target", p - 1, SEED); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); - // ... and "real" is the traditional caller. This is not a typo. - let real: T::AccountId = whitelisted_caller(); - let real_lookup = T::Lookup::unlookup(real.clone()); - add_announcements::(a, Some(caller.clone()), None)?; - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - let call_hash = T::CallHasher::hash_of(&call); - }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) - verify { - assert_last_event::(Event::Announced { real, proxy: caller, call_hash }.into()); - } - - add_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - let caller: T::AccountId = whitelisted_caller(); - let real = T::Lookup::unlookup(account("target", T::MaxProxies::get(), SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - real, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { - let (proxies, _) = Proxies::::get(caller); - assert_eq!(proxies.len() as u32, p + 1); - } - - remove_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - let caller: T::AccountId = whitelisted_caller(); - let delegate = T::Lookup::unlookup(account("target", 0, SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - delegate, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { - let (proxies, _) = Proxies::::get(caller); - assert_eq!(proxies.len() as u32, p - 1); - } - - remove_proxies { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller.clone())) - verify { - let (proxies, _) = Proxies::::get(caller); - assert_eq!(proxies.len() as u32, 0); - } - - create_pure { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; - let caller: T::AccountId = whitelisted_caller(); - }: _( - RawOrigin::Signed(caller.clone()), - T::ProxyType::default(), - BlockNumberFor::::zero(), - 0, - false - ) - verify { - let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::PureCreated { - pure: pure_account, - who: caller, - proxy_type: T::ProxyType::default(), - disambiguation_index: 0, - }.into()); - } - - kill_pure { - let p in 0 .. (T::MaxProxies::get() - 2); - - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - Pallet::::create_pure( - RawOrigin::Signed(whitelisted_caller()).into(), - T::ProxyType::default(), - BlockNumberFor::::zero(), - 0, - false - )?; - let height = system::Pallet::::block_number(); - let ext_index = system::Pallet::::extrinsic_index().unwrap_or(0); - let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - - add_proxies::(p, Some(pure_account.clone()))?; - ensure!(Proxies::::contains_key(&pure_account), "pure proxy not created"); - }: _(RawOrigin::Signed(pure_account.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) - verify { - assert!(!Proxies::::contains_key(&pure_account)); - } - - impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); -} diff --git a/pallets/proxy/src/lib.rs b/pallets/proxy/src/lib.rs deleted file mode 100644 index 1709623..0000000 --- a/pallets/proxy/src/lib.rs +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -//! # Proxy Pallet -//! A pallet allowing accounts to give permission to other accounts to dispatch types of calls from -//! their signed origin. -//! -//! The accounts to which permission is delegated may be required to announce the action that they -//! wish to execute some duration prior to execution happens. In this case, the target account may -//! reject the announcement and in doing so, veto the execution. -//! -//! - [`Config`] -//! - [`Call`] - -// Ensure we're `no_std` when compiling for Wasm. -#![cfg_attr(not(feature = "std"), no_std)] - -mod benchmarking; -mod tests; -pub mod weights; - -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::GetDispatchInfo, - ensure, - traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, -}; -use frame_system::{self as system, ensure_signed, pallet_prelude::BlockNumberFor}; -pub use pallet::*; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{Dispatchable, Hash, Saturating, StaticLookup, TrailingZeroInput, Zero}, - DispatchError, DispatchResult, RuntimeDebug, -}; -use sp_std::prelude::*; -pub use weights::WeightInfo; - -type CallHashOf = <::CallHasher as Hash>::Output; - -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; - -/// The parameters under which a particular account has a proxy relationship with some other -/// account. -#[derive( - Encode, - Decode, - Clone, - Copy, - Eq, - PartialEq, - Ord, - PartialOrd, - RuntimeDebug, - MaxEncodedLen, - TypeInfo, -)] -pub struct ProxyDefinition { - /// The account which may act on behalf of another. - pub delegate: Option, - /// A value defining the subset of calls that it is allowed to make. - pub proxy_type: ProxyType, - /// The number of blocks that an announcement must be in place for before the corresponding - /// call may be dispatched. If zero, then no announcement is needed. - pub delay: BlockNumber, -} - -/// Details surrounding a specific instance of an announcement to make a call. -#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct Announcement { - /// The account which made the announcement. - real: AccountId, - /// The hash of the call to be made. - call_hash: Hash, - /// The height at which the announcement was made. - height: BlockNumber, -} - -#[frame_support::pallet] -pub mod pallet { - use super::{DispatchResult, *}; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - pub struct Pallet(_); - - /// Configuration trait. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The overarching call type. - type RuntimeCall: Parameter - + Dispatchable - + GetDispatchInfo - + From> - + IsSubType> - + IsType<::RuntimeCall>; - - /// The currency mechanism. - type Currency: ReservableCurrency; - - /// A kind of proxy; specified with the proxy and passed in to the `IsProxyable` fitler. - /// The instance filter determines whether a given call may be proxied under this type. - /// - /// IMPORTANT: `Default` must be provided and MUST BE the the *most permissive* value. - type ProxyType: Parameter - + Member - + Ord - + PartialOrd - + InstanceFilter<::RuntimeCall> - + Default - + MaxEncodedLen; - - /// The base amount of currency needed to reserve for creating a proxy. - /// - /// This is held for an additional storage item whose value size is - /// `sizeof(Balance)` bytes and whose key size is `sizeof(AccountId)` bytes. - #[pallet::constant] - type ProxyDepositBase: Get>; - - /// The amount of currency needed per proxy added. - /// - /// This is held for adding 32 bytes plus an instance of `ProxyType` more into a - /// pre-existing storage value. Thus, when configuring `ProxyDepositFactor` one should take - /// into account `32 + proxy_type.encode().len()` bytes of data. - #[pallet::constant] - type ProxyDepositFactor: Get>; - - /// The maximum amount of proxies allowed for a single account. - #[pallet::constant] - type MaxProxies: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// The maximum amount of time-delayed announcements that are allowed to be pending. - #[pallet::constant] - type MaxPending: Get; - - /// The type of hash used for hashing the call. - type CallHasher: Hash; - - /// The base amount of currency needed to reserve for creating an announcement. - /// - /// This is held when a new storage item holding a `Balance` is created (typically 16 - /// bytes). - #[pallet::constant] - type AnnouncementDepositBase: Get>; - - /// The amount of currency needed per announcement made. - /// - /// This is held for adding an `AccountId`, `Hash` and `BlockNumber` (typically 68 bytes) - /// into a pre-existing storage value. - #[pallet::constant] - type AnnouncementDepositFactor: Get>; - } - - #[pallet::call] - impl Pallet { - /// Dispatch the given `call` from an account that the sender is authorised for through - /// `add_proxy`. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `real`: The account that the proxy will make a call on behalf of. - /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. - /// - `call`: The call to be made by the `real` account. - #[pallet::call_index(0)] - #[pallet::weight({ - let di = call.get_dispatch_info(); - (T::WeightInfo::proxy(T::MaxProxies::get()) - // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(di.weight), - di.class) - })] - pub fn proxy( - origin: OriginFor, - real: AccountIdLookupOf, - force_proxy_type: Option, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let real = T::Lookup::lookup(real)?; - let def = Self::find_proxy(&real, Some(who), force_proxy_type)?; - ensure!(def.delay.is_zero(), Error::::Unannounced); - - Self::do_proxy(def, real, *call); - - Ok(()) - } - - /// Register a proxy account for the sender that is able to make calls on its behalf. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `delegate`: The account that the `caller` would like to make a proxy. - /// - `proxy_type`: The permissions allowed for this proxy account. - /// - `delay`: The announcement period required of the initial proxy. - /// zero. - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] - pub fn add_proxy( - origin: OriginFor, - delegate: AccountIdLookupOf, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - Self::add_proxy_delegate(&who, delegate, proxy_type, delay) - } - - /// Unregister a proxy account for the sender. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `delegate`: The account that the `caller` would like to remove as a proxy. - /// - `proxy_type`: The permissions currently enabled for the removed proxy account. - /// - `delay`: The announcement period required of the initial proxy. - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] - pub fn remove_proxy( - origin: OriginFor, - delegate: AccountIdLookupOf, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - Self::remove_proxy_delegate(&who, delegate, proxy_type, delay) - } - - /// Unregister all proxy accounts for the sender. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// WARNING: This may be called on accounts created by `pure`, however if done, then - /// the unreserved fees will be inaccessible. **All access to this account will be lost.** - #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))] - pub fn remove_proxies(origin: OriginFor) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::remove_all_proxy_delegates(&who); - Ok(()) - } - - /// Spawn a fresh new account that is guaranteed to be otherwise inaccessible, and - /// initialize it with a proxy of `proxy_type` for `origin` sender. - /// - /// Requires a `Signed` origin. - /// - /// - `proxy_type`: The type of the proxy that the sender will be registered as over the - /// new account. This will almost always be the most permissive `ProxyType` possible to - /// allow for maximum flexibility. - /// - `delay`: The announcement period required of the initial proxy. Will generally be - /// zero. - /// - `index`: A disambiguation index, in case this is called multiple times in the same - /// transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just - /// want to use `0`. - /// - `anonymous`: Whether the account should be anonymous. - /// - /// Fails with `Duplicate` if this has already been called in this transaction, from the - /// same sender, with the same parameters. - /// - /// Fails if there are insufficient funds to pay for deposit. - #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))] - pub fn create_pure( - origin: OriginFor, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - index: u16, - anonymous: bool, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - let pure = Self::pure_account(&who, &proxy_type, index, None); - ensure!(!Proxies::::contains_key(&pure), Error::::Duplicate); - - // if anonymous, then set no delegate - let delegate = if anonymous { None } else { Some(who.clone()) }; - - let proxy_def = ProxyDefinition { delegate, proxy_type: proxy_type.clone(), delay }; - let bounded_proxies: BoundedVec<_, T::MaxProxies> = - vec![proxy_def].try_into().map_err(|_| Error::::TooMany)?; - - let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get(); - T::Currency::reserve(&who, deposit)?; - - Proxies::::insert(&pure, (bounded_proxies, deposit)); - Self::deposit_event(Event::PureCreated { - pure, - who, - proxy_type, - disambiguation_index: index, - }); - - Ok(()) - } - - /// Removes a previously spawned pure proxy. - /// - /// WARNING: **All access to this account will be lost.** Any funds held in it will be - /// inaccessible. - /// - /// Requires a `Signed` origin, and the sender account must have been created by a call to - /// `pure` with corresponding parameters. - /// - /// - `spawner`: The account that originally called `pure` to create this account. - /// - `proxy_type`: The proxy type originally passed to `pure`. - /// - `index`: The disambiguation index originally passed to `pure`. Probably `0`. - /// - `height`: The height of the chain when the call to `pure` was processed. - /// - `ext_index`: The extrinsic index in which the call to `pure` was processed. - /// - /// Fails with `NoPermission` in case the caller is not a previously created pure - /// account whose `pure` call has corresponding parameters. - #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))] - pub fn kill_pure( - origin: OriginFor, - spawner: AccountIdLookupOf, - proxy_type: T::ProxyType, - index: u16, - #[pallet::compact] height: BlockNumberFor, - #[pallet::compact] ext_index: u32, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let spawner = T::Lookup::lookup(spawner)?; - - let when = (height, ext_index); - let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when)); - ensure!(proxy == who, Error::::NoPermission); - - let (_, deposit) = Proxies::::take(&who); - T::Currency::unreserve(&spawner, deposit); - - Ok(()) - } - - /// Publish the hash of a proxy-call that will be made in the future. - /// - /// This must be called some number of blocks before the corresponding `proxy` is attempted - /// if the delay associated with the proxy relationship is greater than zero. - /// - /// No more than `MaxPending` announcements may be made at any one time. - /// - /// This will take a deposit of `AnnouncementDepositFactor` as well as - /// `AnnouncementDepositBase` if there are no other pending announcements. - /// - /// The dispatch origin for this call must be _Signed_ and a proxy of `real`. - /// - /// Parameters: - /// - `real`: The account that the proxy will make a call on behalf of. - /// - `call_hash`: The hash of the call to be made by the `real` account. - #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] - pub fn announce( - origin: OriginFor, - real: AccountIdLookupOf, - call_hash: CallHashOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let real = T::Lookup::lookup(real)?; - Proxies::::get(&real) - .0 - .into_iter() - .find(|x| x.delegate == Some(who.clone())) - .ok_or(Error::::NotProxy)?; - - let announcement = Announcement { - real: real.clone(), - call_hash, - height: system::Pallet::::block_number(), - }; - - Announcements::::try_mutate(&who, |(ref mut pending, ref mut deposit)| { - pending.try_push(announcement).map_err(|_| Error::::TooMany)?; - Self::rejig_deposit( - &who, - *deposit, - T::AnnouncementDepositBase::get(), - T::AnnouncementDepositFactor::get(), - pending.len(), - ) - .map(|d| { - d.expect("Just pushed; pending.len() > 0; rejig_deposit returns Some; qed") - }) - .map(|d| *deposit = d) - })?; - Self::deposit_event(Event::Announced { real, proxy: who, call_hash }); - - Ok(()) - } - - /// Remove a given announcement. - /// - /// May be called by a proxy account to remove a call they previously announced and return - /// the deposit. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `real`: The account that the proxy will make a call on behalf of. - /// - `call_hash`: The hash of the call to be made by the `real` account. - #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::remove_announcement( - T::MaxPending::get(), - T::MaxProxies::get() - ))] - pub fn remove_announcement( - origin: OriginFor, - real: AccountIdLookupOf, - call_hash: CallHashOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let real = T::Lookup::lookup(real)?; - Self::edit_announcements(&who, |ann| ann.real != real || ann.call_hash != call_hash)?; - - Ok(()) - } - - /// Remove the given announcement of a delegate. - /// - /// May be called by a target (proxied) account to remove a call that one of their delegates - /// (`delegate`) has announced they want to execute. The deposit is returned. - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `delegate`: The account that previously announced the call. - /// - `call_hash`: The hash of the call to be made. - #[pallet::call_index(8)] - #[pallet::weight(T::WeightInfo::reject_announcement( - T::MaxPending::get(), - T::MaxProxies::get() - ))] - pub fn reject_announcement( - origin: OriginFor, - delegate: AccountIdLookupOf, - call_hash: CallHashOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - Self::edit_announcements(&delegate, |ann| { - ann.real != who || ann.call_hash != call_hash - })?; - - Ok(()) - } - - /// Dispatch the given `call` from an account that the sender is authorized for through - /// `add_proxy`. - /// - /// Removes any corresponding announcement(s). - /// - /// The dispatch origin for this call must be _Signed_. - /// - /// Parameters: - /// - `delegate`: The account that the `caller` would like to make a proxy. - /// - `real`: The account that the proxy will make a call on behalf of. - /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. - /// - `call`: The call to be made by the `real` account. - #[pallet::call_index(9)] - #[pallet::weight({ - let di = call.get_dispatch_info(); - (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) - // AccountData for inner call origin accountdata. - .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(di.weight), - di.class) - })] - pub fn proxy_announced( - origin: OriginFor, - delegate: AccountIdLookupOf, - real: AccountIdLookupOf, - force_proxy_type: Option, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - let real = T::Lookup::lookup(real)?; - let def = Self::find_proxy(&real, Some(delegate.clone()), force_proxy_type)?; - - let call_hash = T::CallHasher::hash_of(&call); - let now = system::Pallet::::block_number(); - Self::edit_announcements(&delegate.clone(), |ann| { - ann.real != real || - ann.call_hash != call_hash || - now.saturating_sub(ann.height) < def.delay - }) - .map_err(|_| Error::::Unannounced)?; - - Self::do_proxy(def, real, *call); - - Ok(()) - } - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A proxy was executed correctly, with the given. - ProxyExecuted { result: DispatchResult }, - /// A pure account has been created by new proxy with given - /// disambiguation index and proxy type. - PureCreated { - pure: T::AccountId, - who: T::AccountId, - proxy_type: T::ProxyType, - disambiguation_index: u16, - }, - /// An announcement was placed to make a call in the future. - Announced { real: T::AccountId, proxy: T::AccountId, call_hash: CallHashOf }, - /// A proxy was added. - ProxyAdded { - delegator: T::AccountId, - delegatee: T::AccountId, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - }, - /// A proxy was removed. - ProxyRemoved { - delegator: T::AccountId, - delegatee: T::AccountId, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - }, - } - - #[pallet::error] - pub enum Error { - /// There are too many proxies registered or too many announcements pending. - TooMany, - /// Proxy registration not found. - NotFound, - /// Sender is not a proxy of the account to be proxied. - NotProxy, - /// A call which is incompatible with the proxy type's filter was attempted. - Unproxyable, - /// Account is already a proxy. - Duplicate, - /// Call may not be made by proxy because it may escalate its privileges. - NoPermission, - /// Announcement, if made at all, was made too recently. - Unannounced, - /// Cannot add self as proxy. - NoSelfProxy, - } - - /// The set of account proxies. Maps the account which has delegated to the accounts - /// which are being delegated to, together with the amount held on deposit. - #[pallet::storage] - #[pallet::getter(fn proxies)] - pub type Proxies = StorageMap< - _, - Twox64Concat, - T::AccountId, - ( - BoundedVec< - ProxyDefinition>, - T::MaxProxies, - >, - BalanceOf, - ), - ValueQuery, - >; - - /// The announcements made by the proxy (key). - #[pallet::storage] - #[pallet::getter(fn announcements)] - pub type Announcements = StorageMap< - _, - Twox64Concat, - T::AccountId, - ( - BoundedVec, BlockNumberFor>, T::MaxPending>, - BalanceOf, - ), - ValueQuery, - >; -} - -impl Pallet { - /// Calculate the address of an pure account. - /// - /// - `who`: The spawner account. - /// - `proxy_type`: The type of the proxy that the sender will be registered as over the - /// new account. This will almost always be the most permissive `ProxyType` possible to - /// allow for maximum flexibility. - /// - `index`: A disambiguation index, in case this is called multiple times in the same - /// transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just - /// want to use `0`. - /// - `maybe_when`: The block height and extrinsic index of when the pure account was - /// created. None to use current block height and extrinsic index. - pub fn pure_account( - who: &T::AccountId, - proxy_type: &T::ProxyType, - index: u16, - maybe_when: Option<(BlockNumberFor, u32)>, - ) -> T::AccountId { - let (height, ext_index) = maybe_when.unwrap_or_else(|| { - ( - system::Pallet::::block_number(), - system::Pallet::::extrinsic_index().unwrap_or_default(), - ) - }); - let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index) - .using_encoded(blake2_256); - Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) - .expect("infinite length input; no invalid inputs for type; qed") - } - - /// Register a proxy account for the delegator that is able to make calls on its behalf. - /// - /// Parameters: - /// - `delegator`: The delegator account. - /// - `delegatee`: The account that the `delegator` would like to make a proxy. - /// - `proxy_type`: The permissions allowed for this proxy account. - /// - `delay`: The announcement period required of the initial proxy. Will generally be - /// zero. - pub fn add_proxy_delegate( - delegator: &T::AccountId, - delegatee: T::AccountId, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - ) -> DispatchResult { - ensure!(delegator != &delegatee, Error::::NoSelfProxy); - Proxies::::try_mutate(delegator, |(ref mut proxies, ref mut deposit)| { - let proxy_def = ProxyDefinition { - delegate: Some(delegatee.clone()), - proxy_type: proxy_type.clone(), - delay, - }; - let i = proxies.binary_search(&proxy_def).err().ok_or(Error::::Duplicate)?; - proxies.try_insert(i, proxy_def).map_err(|_| Error::::TooMany)?; - let new_deposit = Self::deposit(proxies.len() as u32); - if new_deposit > *deposit { - T::Currency::reserve(delegator, new_deposit - *deposit)?; - } else if new_deposit < *deposit { - T::Currency::unreserve(delegator, *deposit - new_deposit); - } - *deposit = new_deposit; - Self::deposit_event(Event::::ProxyAdded { - delegator: delegator.clone(), - delegatee, - proxy_type, - delay, - }); - Ok(()) - }) - } - - /// Unregister a proxy account for the delegator. - /// - /// Parameters: - /// - `delegator`: The delegator account. - /// - `delegatee`: The account that the `delegator` would like to make a proxy. - /// - `proxy_type`: The permissions allowed for this proxy account. - /// - `delay`: The announcement period required of the initial proxy. - /// zero. - pub fn remove_proxy_delegate( - delegator: &T::AccountId, - delegatee: T::AccountId, - proxy_type: T::ProxyType, - delay: BlockNumberFor, - ) -> DispatchResult { - Proxies::::try_mutate_exists(delegator, |x| { - let (mut proxies, old_deposit) = x.take().ok_or(Error::::NotFound)?; - let proxy_def = ProxyDefinition { - delegate: Some(delegatee.clone()), - proxy_type: proxy_type.clone(), - delay, - }; - let i = proxies.binary_search(&proxy_def).ok().ok_or(Error::::NotFound)?; - proxies.remove(i); - let new_deposit = Self::deposit(proxies.len() as u32); - if new_deposit > old_deposit { - T::Currency::reserve(delegator, new_deposit - old_deposit)?; - } else if new_deposit < old_deposit { - T::Currency::unreserve(delegator, old_deposit - new_deposit); - } - if !proxies.is_empty() { - *x = Some((proxies, new_deposit)) - } - Self::deposit_event(Event::::ProxyRemoved { - delegator: delegator.clone(), - delegatee, - proxy_type, - delay, - }); - Ok(()) - }) - } - - pub fn deposit(num_proxies: u32) -> BalanceOf { - if num_proxies == 0 { - Zero::zero() - } else { - T::ProxyDepositBase::get() + T::ProxyDepositFactor::get() * num_proxies.into() - } - } - - fn rejig_deposit( - who: &T::AccountId, - old_deposit: BalanceOf, - base: BalanceOf, - factor: BalanceOf, - len: usize, - ) -> Result>, DispatchError> { - let new_deposit = - if len == 0 { BalanceOf::::zero() } else { base + factor * (len as u32).into() }; - if new_deposit > old_deposit { - T::Currency::reserve(who, new_deposit - old_deposit)?; - } else if new_deposit < old_deposit { - T::Currency::unreserve(who, old_deposit - new_deposit); - } - Ok(if len == 0 { None } else { Some(new_deposit) }) - } - - fn edit_announcements< - F: FnMut(&Announcement, BlockNumberFor>) -> bool, - >( - delegate: &T::AccountId, - f: F, - ) -> DispatchResult { - Announcements::::try_mutate_exists(delegate, |x| { - let (mut pending, old_deposit) = x.take().ok_or(Error::::NotFound)?; - let orig_pending_len = pending.len(); - pending.retain(f); - ensure!(orig_pending_len > pending.len(), Error::::NotFound); - *x = Self::rejig_deposit( - delegate, - old_deposit, - T::AnnouncementDepositBase::get(), - T::AnnouncementDepositFactor::get(), - pending.len(), - )? - .map(|deposit| (pending, deposit)); - Ok(()) - }) - } - - pub fn find_proxy( - real: &T::AccountId, - delegate: Option, - force_proxy_type: Option, - ) -> Result>, DispatchError> { - let f = |x: &ProxyDefinition>| -> bool { - x.delegate.clone() == delegate && - force_proxy_type.as_ref().map_or(true, |y| &x.proxy_type == y) - }; - Ok(Proxies::::get(real).0.into_iter().find(f).ok_or(Error::::NotProxy)?) - } - - pub fn do_proxy( - def: ProxyDefinition>, - real: T::AccountId, - call: ::RuntimeCall, - ) { - // This is a freshly authenticated new account, the origin restrictions doesn't apply. - let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into(); - origin.add_filter(move |c: &::RuntimeCall| { - let c = ::RuntimeCall::from_ref(c); - // We make sure the proxy call does access this pallet to change modify proxies. - match c.is_sub_type() { - // Proxy call cannot add or remove a proxy with more permissions than it already - // has. - Some(Call::add_proxy { ref proxy_type, .. }) | - Some(Call::remove_proxy { ref proxy_type, .. }) - if !def.proxy_type.is_superset(proxy_type) => - false, - // Proxy call cannot remove all proxies or kill pure proxies unless it has full - // permissions. - Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. }) - if def.proxy_type != T::ProxyType::default() => - false, - _ => def.proxy_type.filter(c), - } - }); - let e = call.dispatch(origin); - Self::deposit_event(Event::ProxyExecuted { result: e.map(|_| ()).map_err(|e| e.error) }); - } - - /// Removes all proxy delegates for a given delegator. - /// - /// Parameters: - /// - `delegator`: The delegator account. - pub fn remove_all_proxy_delegates(delegator: &T::AccountId) { - let (_, old_deposit) = Proxies::::take(&delegator); - T::Currency::unreserve(&delegator, old_deposit); - } -} diff --git a/pallets/proxy/src/tests.rs b/pallets/proxy/src/tests.rs deleted file mode 100644 index 71dbcbb..0000000 --- a/pallets/proxy/src/tests.rs +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -// Tests for Proxy Pallet - -#![cfg(test)] - -use super::*; - -use crate as proxy; -use codec::{Decode, Encode}; -use frame_support::{ - assert_noop, assert_ok, derive_impl, - traits::{ConstU32, ConstU64, Contains}, -}; -use sp_core::H256; -use sp_runtime::{traits::BlakeTwo256, BuildStorage, DispatchError, RuntimeDebug}; - -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Proxy: proxy, - Utility: pallet_utility, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; - type BaseCallFilter = BaseFilter; - type AccountData = pallet_balances::AccountData; -} - -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] -impl pallet_balances::Config for Test { - type ReserveIdentifier = [u8; 8]; - type AccountStore = System; -} - -impl pallet_utility::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = (); -} - -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - Any, - JustTransfer, - JustUtility, -} -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::JustTransfer => { - matches!( - c, - RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) - ) - }, - ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), - } - } - fn is_superset(&self, o: &Self) -> bool { - self == &ProxyType::Any || self == o - } -} -pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(c: &RuntimeCall) -> bool { - match *c { - // Remark is used as a no-op call in the benchmarking - RuntimeCall::System(SystemCall::remark { .. }) => true, - RuntimeCall::System(_) => false, - _ => true, - } - } -} -impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - type ProxyDepositBase = ConstU64<1>; - type ProxyDepositFactor = ConstU64<1>; - type MaxProxies = ConstU32<4>; - type WeightInfo = (); - type CallHasher = BlakeTwo256; - type MaxPending = ConstU32<2>; - type AnnouncementDepositBase = ConstU64<1>; - type AnnouncementDepositFactor = ConstU64<1>; -} - -use super::{Call as ProxyCall, Event as ProxyEvent}; -use frame_system::Call as SystemCall; -use pallet_balances::{Call as BalancesCall, Event as BalancesEvent}; -use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; - -type SystemError = frame_system::Error; - -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 3)], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -fn last_events(n: usize) -> Vec { - system::Pallet::::events() - .into_iter() - .rev() - .take(n) - .rev() - .map(|e| e.event) - .collect() -} - -fn expect_events(e: Vec) { - assert_eq!(last_events(e.len()), e); -} - -fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) -} - -#[test] -fn announcement_works() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); - System::assert_last_event( - ProxyEvent::ProxyAdded { - delegator: 1, - delegatee: 3, - proxy_type: ProxyType::Any, - delay: 1, - } - .into(), - ); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); - assert_eq!(Balances::reserved_balance(3), 0); - - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); - let announcements = Announcements::::get(3); - assert_eq!( - announcements.0, - vec![Announcement { real: 1, call_hash: [1; 32].into(), height: 1 }] - ); - assert_eq!(Balances::reserved_balance(3), announcements.1); - - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); - let announcements = Announcements::::get(3); - assert_eq!( - announcements.0, - vec![ - Announcement { real: 1, call_hash: [1; 32].into(), height: 1 }, - Announcement { real: 2, call_hash: [2; 32].into(), height: 1 }, - ] - ); - assert_eq!(Balances::reserved_balance(3), announcements.1); - - assert_noop!( - Proxy::announce(RuntimeOrigin::signed(3), 2, [3; 32].into()), - Error::::TooMany - ); - }); -} - -#[test] -fn remove_announcement_works() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); - let e = Error::::NotFound; - assert_noop!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [0; 32].into()), e); - assert_ok!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [1; 32].into())); - let announcements = Announcements::::get(3); - assert_eq!( - announcements.0, - vec![Announcement { real: 2, call_hash: [2; 32].into(), height: 1 }] - ); - assert_eq!(Balances::reserved_balance(3), announcements.1); - }); -} - -#[test] -fn reject_announcement_works() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); - let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [0; 32].into()), e); - let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(4), 3, [1; 32].into()), e); - assert_ok!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [1; 32].into())); - let announcements = Announcements::::get(3); - assert_eq!( - announcements.0, - vec![Announcement { real: 2, call_hash: [2; 32].into(), height: 1 }] - ); - assert_eq!(Balances::reserved_balance(3), announcements.1); - }); -} - -#[test] -fn announcer_must_be_proxy() { - new_test_ext().execute_with(|| { - assert_noop!( - Proxy::announce(RuntimeOrigin::signed(2), 1, H256::zero()), - Error::::NotProxy - ); - }); -} - -#[test] -fn calling_proxy_doesnt_remove_announcement() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); - - let call = Box::new(call_transfer(6, 1)); - let call_hash = BlakeTwo256::hash_of(&call); - - assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call)); - - // The announcement is not removed by calling proxy. - let announcements = Announcements::::get(2); - assert_eq!(announcements.0, vec![Announcement { real: 1, call_hash, height: 1 }]); - }); -} - -#[test] -fn delayed_requires_pre_announcement() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 1)); - let call = Box::new(call_transfer(6, 1)); - let e = Error::::Unannounced; - assert_noop!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone()), e); - let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone()), e); - let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); - system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone())); - }); -} - -#[test] -fn proxy_announced_removes_announcement_and_returns_deposit() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); - let call = Box::new(call_transfer(6, 1)); - let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, call_hash)); - assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, call_hash)); - // Too early to execute announced call - let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone()), e); - - system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone())); - let announcements = Announcements::::get(3); - assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1 }]); - assert_eq!(Balances::reserved_balance(3), announcements.1); - }); -} - -#[test] -fn filtering_works() { - new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 1000); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); - - let call = Box::new(call_transfer(6, 1)); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - - let derivative_id = Utility::derivative_account_id(1, 0); - Balances::make_free_balance_be(&derivative_id, 1000); - let inner = Box::new(call_transfer(6, 1)); - - let call = Box::new(RuntimeCall::Utility(UtilityCall::as_derivative { - index: 0, - call: inner.clone(), - })); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); - expect_events(vec![ - UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - - let inner = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_add_proxy( - 5, - ProxyType::Any, - 0, - ))); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); - expect_events(vec![ - UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - - let call = Box::new(RuntimeCall::Proxy(ProxyCall::remove_proxies {})); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - expect_events(vec![ - BalancesEvent::::Unreserved { who: 1, amount: 5 }.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); -} - -#[test] -fn add_remove_proxies_works() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); - assert_noop!( - Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0), - Error::::Duplicate - ); - assert_eq!(Balances::reserved_balance(1), 2); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); - assert_eq!(Balances::reserved_balance(1), 3); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); - assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); - assert_eq!(Balances::reserved_balance(1), 5); - assert_noop!( - Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::Any, 0), - Error::::TooMany - ); - assert_noop!( - Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0), - Error::::NotFound - ); - assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); - System::assert_last_event( - ProxyEvent::ProxyRemoved { - delegator: 1, - delegatee: 4, - proxy_type: ProxyType::JustUtility, - delay: 0, - } - .into(), - ); - assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); - assert_eq!(Balances::reserved_balance(1), 3); - System::assert_last_event( - ProxyEvent::ProxyRemoved { - delegator: 1, - delegatee: 3, - proxy_type: ProxyType::Any, - delay: 0, - } - .into(), - ); - assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); - assert_eq!(Balances::reserved_balance(1), 2); - System::assert_last_event( - ProxyEvent::ProxyRemoved { - delegator: 1, - delegatee: 2, - proxy_type: ProxyType::Any, - delay: 0, - } - .into(), - ); - assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); - assert_eq!(Balances::reserved_balance(1), 0); - System::assert_last_event( - ProxyEvent::ProxyRemoved { - delegator: 1, - delegatee: 2, - proxy_type: ProxyType::JustTransfer, - delay: 0, - } - .into(), - ); - assert_noop!( - Proxy::add_proxy(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0), - Error::::NoSelfProxy - ); - }); -} - -#[test] -fn cannot_add_proxy_without_balance() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(5), 3, ProxyType::Any, 0)); - assert_eq!(Balances::reserved_balance(5), 2); - assert_noop!( - Proxy::add_proxy(RuntimeOrigin::signed(5), 4, ProxyType::Any, 0), - DispatchError::ConsumerRemaining, - ); - }); -} - -#[test] -fn proxying_works() { - new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); - - let call = Box::new(call_transfer(6, 1)); - assert_noop!( - Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone()), - Error::::NotProxy - ); - assert_noop!( - Proxy::proxy(RuntimeOrigin::signed(2), 1, Some(ProxyType::Any), call.clone()), - Error::::NotProxy - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_eq!(Balances::free_balance(6), 1); - - let call = Box::new(RuntimeCall::System(SystemCall::set_code { code: vec![] })); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - - let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_keep_alive { - dest: 6, - value: 1, - })); - assert_ok!(RuntimeCall::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) - .dispatch(RuntimeOrigin::signed(2))); - System::assert_last_event( - ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), - ); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_eq!(Balances::free_balance(6), 2); - }); -} - -#[test] -fn pure_works() { - new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 11); // An extra one for the ED. - assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0, false)); - let anon = Proxy::pure_account(&1, &ProxyType::Any, 0, None); - System::assert_last_event( - ProxyEvent::PureCreated { - pure: anon, - who: 1, - proxy_type: ProxyType::Any, - disambiguation_index: 0, - } - .into(), - ); - - // other calls to pure allowed as long as they're not exactly the same. - assert_ok!(Proxy::create_pure( - RuntimeOrigin::signed(1), - ProxyType::JustTransfer, - 0, - 0, - false - )); - assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 1, false)); - let anon2 = Proxy::pure_account(&2, &ProxyType::Any, 0, None); - assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(2), ProxyType::Any, 0, 0, false)); - assert_noop!( - Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0, false), - Error::::Duplicate - ); - System::set_extrinsic_index(1); - assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0, false)); - System::set_extrinsic_index(0); - System::set_block_number(2); - assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0, false)); - - let call = Box::new(call_transfer(6, 1)); - assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), anon, 5)); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call)); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_eq!(Balances::free_balance(6), 1); - - let call = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_kill_pure( - 1, - ProxyType::Any, - 0, - 1, - 0, - ))); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), anon2, None, call.clone())); - let de = DispatchError::from(Error::::NoPermission).stripped(); - System::assert_last_event(ProxyEvent::ProxyExecuted { result: Err(de) }.into()); - assert_noop!( - Proxy::kill_pure(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), - Error::::NoPermission - ); - assert_eq!(Balances::free_balance(1), 1); - assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone())); - assert_eq!(Balances::free_balance(1), 3); - assert_noop!( - Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone()), - Error::::NotProxy - ); - }); -} diff --git a/pallets/proxy/src/weights.rs b/pallets/proxy/src/weights.rs deleted file mode 100644 index 53e2724..0000000 --- a/pallets/proxy/src/weights.rs +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -//! Autogenerated weights for pallet_proxy -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/substrate -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_proxy -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/proxy/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for pallet_proxy. -pub trait WeightInfo { - fn proxy(p: u32, ) -> Weight; - fn proxy_announced(a: u32, p: u32, ) -> Weight; - fn remove_announcement(a: u32, p: u32, ) -> Weight; - fn reject_announcement(a: u32, p: u32, ) -> Weight; - fn announce(a: u32, p: u32, ) -> Weight; - fn add_proxy(p: u32, ) -> Weight; - fn remove_proxy(p: u32, ) -> Weight; - fn remove_proxies(p: u32, ) -> Weight; - fn create_pure(p: u32, ) -> Weight; - fn kill_pure(p: u32, ) -> Weight; -} - -/// Weights for pallet_proxy using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 15_182_000 picoseconds. - Weight::from_parts(15_919_146, 4706) - // Standard Error: 1_586 - .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `488 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 40_256_000 picoseconds. - Weight::from_parts(40_373_648, 5698) - // Standard Error: 3_978 - .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) - // Standard Error: 4_110 - .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 25_040_000 picoseconds. - Weight::from_parts(25_112_188, 5698) - // Standard Error: 2_143 - .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_884_000 picoseconds. - Weight::from_parts(25_359_291, 5698) - // Standard Error: 2_019 - .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) - // Standard Error: 2_086 - .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn announce(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `420 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 35_039_000 picoseconds. - Weight::from_parts(36_727_868, 5698) - // Standard Error: 4_463 - .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) - // Standard Error: 4_611 - .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn add_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_697_000 picoseconds. - Weight::from_parts(26_611_090, 4706) - // Standard Error: 2_306 - .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_638_000 picoseconds. - Weight::from_parts(26_904_510, 4706) - // Standard Error: 2_669 - .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxies(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 22_737_000 picoseconds. - Weight::from_parts(23_618_441, 4706) - // Standard Error: 1_729 - .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `4706` - // Minimum execution time: 27_364_000 picoseconds. - Weight::from_parts(28_632_271, 4706) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 30]`. - fn kill_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `198 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_552_000 picoseconds. - Weight::from_parts(24_874_553, 4706) - // Standard Error: 1_919 - .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 15_182_000 picoseconds. - Weight::from_parts(15_919_146, 4706) - // Standard Error: 1_586 - .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `488 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 40_256_000 picoseconds. - Weight::from_parts(40_373_648, 5698) - // Standard Error: 3_978 - .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) - // Standard Error: 4_110 - .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 25_040_000 picoseconds. - Weight::from_parts(25_112_188, 5698) - // Standard Error: 2_143 - .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_884_000 picoseconds. - Weight::from_parts(25_359_291, 5698) - // Standard Error: 2_019 - .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) - // Standard Error: 2_086 - .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn announce(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `420 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 35_039_000 picoseconds. - Weight::from_parts(36_727_868, 5698) - // Standard Error: 4_463 - .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) - // Standard Error: 4_611 - .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn add_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_697_000 picoseconds. - Weight::from_parts(26_611_090, 4706) - // Standard Error: 2_306 - .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_638_000 picoseconds. - Weight::from_parts(26_904_510, 4706) - // Standard Error: 2_669 - .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxies(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `161 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 22_737_000 picoseconds. - Weight::from_parts(23_618_441, 4706) - // Standard Error: 1_729 - .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `4706` - // Minimum execution time: 27_364_000 picoseconds. - Weight::from_parts(28_632_271, 4706) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 30]`. - fn kill_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `198 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_552_000 picoseconds. - Weight::from_parts(24_874_553, 4706) - // Standard Error: 1_919 - .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } -} diff --git a/pallets/randomness-beacon/Cargo.toml b/pallets/randomness-beacon/Cargo.toml index 9a3e911..1c089cd 100644 --- a/pallets/randomness-beacon/Cargo.toml +++ b/pallets/randomness-beacon/Cargo.toml @@ -23,7 +23,6 @@ pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branc pallet-authorship = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } pallet-etf = { path = "../etf", default-features = false } -pallet-beefy = { package = "pallet-beefy-etf", path = "../beefy-etf", default-features = false } sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } sp-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } @@ -49,7 +48,6 @@ sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "te sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-beefy-mmr = { package = "pallet-beefy-mmr-etf", path = "../beefy-mmr-etf" } pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } [features] @@ -79,7 +77,6 @@ std = [ "sp-state-machine/std", "sp-std/std", "pallet-etf/std", - "pallet-beefy/std", "w3f-bls/std", "sha3/std", "sha2/std", diff --git a/pallets/scheduler/Cargo.toml b/pallets/scheduler/Cargo.toml deleted file mode 100644 index 3d5675b..0000000 --- a/pallets/scheduler/Cargo.toml +++ /dev/null @@ -1,75 +0,0 @@ -[package] -name = "pallet-scheduler" -version = "4.0.0-dev" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "FRAME Scheduler pallet" -readme = "README.md" - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -frame-benchmarking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false , optional = true } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-weights = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -docify = "0.2.6" -pallet-randomness-beacon = { default-features = false, path = "../randomness-beacon" } - -[dev-dependencies] -pallet-preimage = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-timestamp = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -substrate-test-utils = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -etf-crypto-primitives = { git = "https://github.com/ideal-lab5/etf-sdk.git" } -ark-std = { version = "0.4.0", default-features = false } -ark-ff = { version = "0.4.0", default-features = false } -ark-poly = { version = "0.4.0", default-features = false } -ark-ec = { version = "0.4.0", default-features = false } -ark-serialize = { version = "0.4.0", default-features = false } -ark-bls12-381 = { version = "0.4.0", features = ["curve"], default-features = false } -ark-crypto-primitives = { version = "0.4.0", default-features = false, features = ["signature"] } -pallet-etf = { default-features = false, path = "../etf" } -pallet-insecure-randomness-collective-flip = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -rand_chacha = { version = "0.3.1", default-features = false } - -[features] -default = [ "std" ] -runtime-benchmarks = [ - "frame-benchmarking", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -std = [ - "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-preimage/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "sp-weights/std", - "pallet-etf/std", - "pallet-timestamp/std", - "pallet-randomness-beacon/std" -] -try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-preimage/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/scheduler/README.md b/pallets/scheduler/README.md deleted file mode 100644 index 6aec2dd..0000000 --- a/pallets/scheduler/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Scheduler -A module for scheduling dispatches. - -- [`scheduler::Config`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/trait.Config.html) -- [`Call`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/enum.Call.html) -- [`Module`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/struct.Module.html) - -## Overview - -This module exposes capabilities for scheduling dispatches to occur at a -specified block number or at a specified period. These scheduled dispatches -may be named or anonymous and may be canceled. - -**NOTE:** The scheduled calls will be dispatched with the default filter -for the origin: namely `frame_system::Config::BaseCallFilter` for all origin -except root which will get no filter. And not the filter contained in origin -use to call `fn schedule`. - -If a call is scheduled using proxy or whatever mecanism which adds filter, -then those filter will not be used when dispatching the schedule call. - -## Interface - -### Dispatchable Functions - -- `schedule` - schedule a dispatch, which may be periodic, to occur at a - specified block and with a specified priority. -- `cancel` - cancel a scheduled dispatch, specified by block number and - index. -- `schedule_named` - augments the `schedule` interface with an additional - `Vec` parameter that can be used for identification. -- `cancel_named` - the named complement to the cancel function. - -License: Apache 2.0 diff --git a/pallets/scheduler/src/benchmarking.rs b/pallets/scheduler/src/benchmarking.rs deleted file mode 100644 index 64bee81..0000000 --- a/pallets/scheduler/src/benchmarking.rs +++ /dev/null @@ -1,361 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! Scheduler pallet benchmarking. - -use super::*; -use frame_benchmarking::v1::{account, benchmarks}; -use frame_support::{ - ensure, - traits::{schedule::Priority, BoundedInline, ConstU32}, -}; -use frame_system::pallet_prelude::BlockNumberFor; -use sp_std::{prelude::*, vec}; - -use crate::Pallet as Scheduler; -use frame_system::Call as SystemCall; - -const SEED: u32 = 0; - -const BLOCK_NUMBER: u32 = 2; - -// type SystemOrigin = ::RuntimeOrigin; - -/// Add `n` items to the schedule. -/// -/// For `resolved`: -/// - ` -/// - `None`: aborted (hash without preimage) -/// - `Some(true)`: hash resolves into call if possible, plain call otherwise -/// - `Some(false)`: plain call -fn fill_schedule( - when: frame_system::pallet_prelude::BlockNumberFor, - n: u32, -) -> Result<(), &'static str> { - let t = DispatchTime::At(when); - let origin: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); - for i in 0..n { - let call = make_call::(None); - let period = Some(((i + 100).into(), 100)); - let name = u32_to_name(i); - Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; - } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) -} - -fn fill_schedule_signed( - when: frame_system::pallet_prelude::BlockNumberFor, - n: u32, -) -> Result<(), &'static str> { - let t = DispatchTime::At(when); - let origin: ::PalletsOrigin = - frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(); - for i in 0..n { - let call = make_call::(None); - let period = Some(((i + 100).into(), 100)); - let name = u32_to_name(i); - Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; - } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) -} - -fn u32_to_name(i: u32) -> TaskName { - i.using_encoded(blake2_256) -} - -fn make_task( - periodic: bool, - named: bool, - signed: bool, - maybe_lookup_len: Option, - priority: Priority, -) -> ScheduledOf { - let call = make_call::(maybe_lookup_len); - let maybe_periodic = match periodic { - true => Some((100u32.into(), 100)), - false => None, - }; - let maybe_id = match named { - true => Some(u32_to_name(0)), - false => None, - }; - let origin = make_origin::(signed); - Scheduled { - maybe_id, - priority, - maybe_ciphertext: None, - maybe_call: Some(call), - maybe_periodic, - origin, - _phantom: PhantomData, - } -} - -fn bounded(len: u32) -> Option> { - let call = - <::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] }); - T::Preimages::bound(call).ok() -} - -fn make_call(maybe_lookup_len: Option) -> BoundedCallOf { - let bound = BoundedInline::bound() as u32; - let mut len = match maybe_lookup_len { - Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3, - None => bound.saturating_sub(4), - }; - - loop { - let c = match bounded::(len) { - Some(x) => x, - None => { - len -= 1; - continue; - }, - }; - if c.lookup_needed() == maybe_lookup_len.is_some() { - break c; - } - if maybe_lookup_len.is_some() { - len += 1; - } else { - if len > 0 { - len -= 1; - } else { - break c; - } - } - } -} - -fn make_origin(signed: bool) -> ::PalletsOrigin { - match signed { - true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(), - false => frame_system::RawOrigin::Root.into(), - } -} - -benchmarks! { - // `service_agendas` when no work is done. - service_agendas_base { - let now = BlockNumberFor::::from(BLOCK_NUMBER); - IncompleteSince::::put(now - One::one()); - }: { - Scheduler::::service_agendas(&mut WeightMeter::new(), now, 0); - } verify { - assert_eq!(IncompleteSince::::get(), Some(now - One::one())); - } - - // `service_agenda` when no work is done. - service_agenda_base { - let now = BLOCK_NUMBER.into(); - let s in 0 .. T::MaxScheduledPerBlock::get(); - fill_schedule::(now, s)?; - let mut executed = 0; - }: { - Scheduler::::service_agenda(&mut WeightMeter::new(), &mut executed, now, now, 0); - } verify { - assert_eq!(executed, 0); - } - - // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not - // dispatched (e.g. due to being overweight). - service_task_base { - let now = BLOCK_NUMBER.into(); - let task = make_task::(false, false, false, None, 0); - // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { - //assert_eq!(result, Ok(())); - } - - // `service_task` when the task is a non-periodic, non-named, fetched call (with a known - // preimage length) and which is not dispatched (e.g. due to being overweight). - #[pov_mode = MaxEncodedLen { - // Use measured PoV size for the Preimages since we pass in a length witness. - Preimage::PreimageFor: Measured - }] - service_task_fetched { - let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32); - let now = BLOCK_NUMBER.into(); - let task = make_task::(false, false, false, Some(s), 0); - // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { - } - - // `service_task` when the task is a non-periodic, named, non-fetched call which is not - // dispatched (e.g. due to being overweight). - service_task_named { - let now = BLOCK_NUMBER.into(); - let task = make_task::(false, true, false, None, 0); - // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { - } - - // `service_task` when the task is a periodic, non-named, non-fetched call which is not - // dispatched (e.g. due to being overweight). - service_task_periodic { - let now = BLOCK_NUMBER.into(); - let task = make_task::(true, false, false, None, 0); - // prevent any tasks from actually being executed as we only want the surrounding weight. - let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { - } - - // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. - execute_dispatch_signed { - let mut counter = WeightMeter::new(); - let origin = make_origin::(true); - let call = T::Preimages::realize(&make_call::(None)).unwrap().0; - }: { - assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); - } - verify { - } - - // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. - execute_dispatch_unsigned { - let mut counter = WeightMeter::new(); - let origin = make_origin::(false); - let call = T::Preimages::realize(&make_call::(None)).unwrap().0; - }: { - assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); - } - verify { - } - - schedule { - let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); - let when = BLOCK_NUMBER.into(); - let periodic = Some((BlockNumberFor::::one(), 100)); - let priority = 0; - // Essentially a no-op call. - let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - let origin = frame_system::RawOrigin::Signed(account("origin", 0, SEED)); - - fill_schedule::(when, s)?; - }: _(origin, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - cancel { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - - fill_schedule_signed::(when, s)?; - assert_eq!(Agenda::::get(when).len(), s as usize); - let origin = frame_system::RawOrigin::Signed(account("origin", 0, SEED)); - }: _(origin, when, 0) - verify { - ensure!( - s == 1 || Lookup::::get(u32_to_name(0)).is_none(), - "didn't remove from lookup if more than 1 task scheduled for `when`" - ); - // Removed schedule is NONE - ensure!( - s == 1 || Agenda::::get(when)[0].is_none(), - "didn't remove from schedule if more than 1 task scheduled for `when`" - ); - ensure!( - s > 1 || Agenda::::get(when).len() == 0, - "remove from schedule if only 1 task scheduled for `when`" - ); - } - - schedule_named { - let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); - let id = u32_to_name(s); - let when = BLOCK_NUMBER.into(); - let periodic = Some((BlockNumberFor::::one(), 100)); - let priority = 0; - // Essentially a no-op call. - let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - let origin = frame_system::RawOrigin::Signed(account("origin", 0, SEED)); - fill_schedule_signed::(when, s)?; - }: _(origin, id, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - cancel_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - let origin = frame_system::RawOrigin::Signed(account("origin", 0, SEED)); - fill_schedule_signed::(when, s)?; - }: _(origin, u32_to_name(0)) - verify { - ensure!( - s == 1 || Lookup::::get(u32_to_name(0)).is_none(), - "didn't remove from lookup if more than 1 task scheduled for `when`" - ); - // Removed schedule is NONE - ensure!( - s == 1 || Agenda::::get(when)[0].is_none(), - "didn't remove from schedule if more than 1 task scheduled for `when`" - ); - ensure!( - s > 1 || Agenda::::get(when).len() == 0, - "remove from schedule if only 1 task scheduled for `when`" - ); - } - - schedule_sealed { - let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); - let when = BLOCK_NUMBER.into(); - let periodic = Some((BlockNumberFor::::one(), 100)); - let priority = 0; - - let bounded_ct: BoundedVec> = BoundedVec::new(); - let bounded_nonce: BoundedVec> = BoundedVec::new(); - let bounded_capsule: BoundedVec> = BoundedVec::new(); - let origin = frame_system::RawOrigin::Signed(account("origin", 0, SEED)); - - let ciphertext = Ciphertext { - ciphertext: bounded_ct, - nonce: bounded_nonce, - capsule: bounded_capsule, - }; - - fill_schedule_signed::(when, s)?; - }: _(origin, when, priority, ciphertext) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); -} diff --git a/pallets/scheduler/src/lib.rs b/pallets/scheduler/src/lib.rs deleted file mode 100644 index 7e46e79..0000000 --- a/pallets/scheduler/src/lib.rs +++ /dev/null @@ -1,1192 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! > Made with *Substrate*, for *Polkadot*. -//! -//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/scheduler) - -//! [![polkadot]](https://polkadot.network) -//! -//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white -//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github -//! -//! # Scheduler Pallet -//! -//! A Pallet for scheduling runtime calls. -//! -//! ## Overview -//! -//! This Pallet exposes capabilities for scheduling runtime calls to occur at a specified block -//! number or at a specified period. These scheduled runtime calls may be named or anonymous and may -//! be canceled. -//! -//! __NOTE:__ Instead of using the filter contained in the origin to call `fn schedule`, scheduled -//! runtime calls will be dispatched with the default filter for the origin: namely -//! `frame_system::Config::BaseCallFilter` for all origin types (except root which will get no -//! filter). -//! -//! If a call is scheduled using proxy or whatever mechanism which adds filter, then those filter -//! will not be used when dispatching the schedule runtime call. -//! -//! ### Examples -//! -//! 1. Scheduling a runtime call at a specific block. -// #![doc = docify::embed!("src/tests.rs", basic_scheduling_works)] -//! -//! 2. Scheduling a preimage hash of a runtime call at a specifc block -// #![doc = docify::embed!("src/tests.rs", scheduling_with_preimages_works)] - -//! -//! ## Pallet API -//! -//! See the [`pallet`] module for more information about the interfaces this pallet exposes, -//! including its configuration trait, dispatchables, storage items, events and errors. -//! -//! ## Warning -//! -//! This Pallet executes all scheduled runtime calls in the [`on_initialize`] hook. Do not execute -//! any runtime calls which should not be considered mandatory. -//! -//! Please be aware that any scheduled runtime calls executed in a future block may __fail__ or may -//! result in __undefined behavior__ since the runtime could have upgraded between the time of -//! scheduling and execution. For example, the runtime upgrade could have: -//! -//! * Modified the implementation of the runtime call (runtime specification upgrade). -//! * Could lead to undefined behavior. -//! * Removed or changed the ordering/index of the runtime call. -//! * Could fail due to the runtime call index not being part of the `Call`. -//! * Could lead to undefined behavior, such as executing another runtime call with the same -//! index. -//! -//! [`on_initialize`]: frame_support::traits::Hooks::on_initialize - -// Ensure we're `no_std` when compiling for Wasm. -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; -pub mod weights; -pub use weights::WeightInfo; - -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::{DispatchResult, GetDispatchInfo, Parameter, RawOrigin}, - ensure, - traits::{ - schedule::{self, DispatchTime, MaybeHashed}, - Bounded, CallerTrait, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, QueryPreimage, - StorageVersion, StorePreimage, - }, - weights::{Weight, WeightMeter}, -}; -use frame_system::{ - pallet_prelude::BlockNumberFor, - {self as system}, -}; -pub use pallet::*; -use pallet_randomness_beacon::TimelockEncryptionProvider; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{BadOrigin, ConstU32, Dispatchable, One, Saturating, Zero}, - BoundedVec, DispatchError, RuntimeDebug, -}; -use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; - -/// Just a simple index for naming period tasks. -pub type PeriodicIndex = u32; -/// The location of a scheduled task that can be used to remove it. -pub type TaskAddress = (BlockNumber, u32); - -pub type CallOrHashOf = - MaybeHashed<::RuntimeCall, ::Hash>; - -pub type BoundedCallOf = - Bounded<::RuntimeCall, ::Hashing>; - -// TODO: ciphertexts can't exceed 4048 (arbitratily) -// we need to determine a better upper bound for this -pub type Ciphertext = BoundedVec>; - -/// Information regarding an item to be executed in the future. -#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] -#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] -pub struct Scheduled { - /// The unique identity for this task, if there is one. - maybe_id: Option, - /// This task's priority. - priority: schedule::Priority, - /// The call to be dispatched. If none, then delayed transactions are used - maybe_call: Option, - /// the delayed call ciphertext - maybe_ciphertext: Option, - /// If the call is periodic, then this points to the information concerning that. - maybe_periodic: Option>, - /// The origin with which to dispatch the call. - origin: PalletsOrigin, - _phantom: PhantomData, -} - -pub type ScheduledOf = Scheduled< - TaskName, - BoundedCallOf, - Ciphertext, - BlockNumberFor, - ::PalletsOrigin, - ::AccountId, ->; - -// expected that WeightInfo is a struct and not a type -pub(crate) trait MarginalWeightInfo: WeightInfo { - fn service_task(maybe_lookup_len: Option, named: bool, periodic: bool) -> Weight { - let base = Self::service_task_base(); - let mut total = match maybe_lookup_len { - None => base, - Some(l) => Self::service_task_fetched(l as u32), - }; - if named { - total.saturating_accrue(Self::service_task_named().saturating_sub(base)); - } - if periodic { - total.saturating_accrue(Self::service_task_periodic().saturating_sub(base)); - } - total - } -} -impl MarginalWeightInfo for T {} - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; - use frame_system::pallet_prelude::*; - - /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); - - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(_); - - /// `system::Config` should always be included in our implied traits. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The aggregated origin which the dispatch will take. - type RuntimeOrigin: OriginTrait - + From - + IsType<::RuntimeOrigin>; - - /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: From> - + CallerTrait - + MaxEncodedLen; - - /// The aggregated call type. - type RuntimeCall: Parameter - + Dispatchable< - RuntimeOrigin = ::RuntimeOrigin, - PostInfo = PostDispatchInfo, - > + GetDispatchInfo - + From>; - - /// The maximum weight that may be scheduled per block for any dispatchables. - #[pallet::constant] - type MaximumWeight: Get; - - /// Required origin to schedule or cancel calls. - type ScheduleOrigin: EnsureOrigin<::RuntimeOrigin>; - - /// Compare the privileges of origins. - /// - /// This will be used when canceling a task, to ensure that the origin that tries - /// to cancel has greater or equal privileges as the origin that created the scheduled task. - /// - /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can - /// be used. This will only check if two given origins are equal. - type OriginPrivilegeCmp: PrivilegeCmp; - - /// The maximum number of scheduled calls in the queue for a single block. - /// - /// NOTE: - /// + Dependent pallets' benchmarks might require a higher limit for the setting. Set a - /// higher limit under `runtime-benchmarks` feature. - #[pallet::constant] - type MaxScheduledPerBlock: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// The preimage provider with which we look up call hashes to get the call. - type Preimages: QueryPreimage + StorePreimage; - - /// something that can decrypt messages locked for the current slot - type TlockProvider: TimelockEncryptionProvider>; - } - - #[pallet::storage] - pub type IncompleteSince = StorageValue<_, BlockNumberFor>; - - /// Items to be executed, indexed by the block number that they should be executed on. - #[pallet::storage] - pub type Agenda = StorageMap< - _, - Twox64Concat, - BlockNumberFor, - BoundedVec>, T::MaxScheduledPerBlock>, - ValueQuery, - >; - - /// Lookup from a name to the block number and index of the task. - /// - /// For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4 - /// identities. - #[pallet::storage] - pub(crate) type Lookup = - StorageMap<_, Twox64Concat, TaskName, TaskAddress>>; - - /// Events type. - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Scheduled some task. - Scheduled { when: BlockNumberFor, index: u32 }, - /// Canceled some task. - Canceled { when: BlockNumberFor, index: u32 }, - /// Dispatched some task. - Dispatched { - task: TaskAddress>, - id: Option, - result: DispatchResult, - }, - /// The call for the provided hash was not found so the task has been aborted. - CallUnavailable { task: TaskAddress>, id: Option }, - /// The given task was unable to be renewed since the agenda is full at that block. - PeriodicFailed { task: TaskAddress>, id: Option }, - /// The given task can never be executed since it is overweight. - PermanentlyOverweight { task: TaskAddress>, id: Option }, - } - - #[pallet::error] - pub enum Error { - /// Failed to schedule a call - FailedToSchedule, - /// Cannot find the scheduled call. - NotFound, - /// Given target block number is in the past. - TargetBlockNumberInPast, - /// Reschedule failed because it does not change scheduled time. - RescheduleNoChange, - /// Attempt to use a non-named function on a named task. - Named, - } - - #[pallet::hooks] - impl Hooks> for Pallet { - /// Execute the scheduled calls - fn on_initialize(now: BlockNumberFor) -> Weight { - let mut weight_counter = WeightMeter::with_limit(T::MaximumWeight::get()); - // first service anything scheduled (non-encrypted) - Self::service_agendas(&mut weight_counter, now, u32::max_value()); - weight_counter.consumed() - } - } - - #[pallet::call] - impl Pallet { - /// Anonymously schedule a task. - #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] - pub fn schedule( - origin: OriginFor, - when: BlockNumberFor, - maybe_periodic: Option>>, - priority: schedule::Priority, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule( - DispatchTime::At(when), - maybe_periodic, - priority, - origin.caller().clone(), - T::Preimages::bound(*call)?, - )?; - Ok(()) - } - - /// Cancel an anonymously scheduled task. - #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] - pub fn cancel(origin: OriginFor, when: BlockNumberFor, index: u32) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_cancel(Some(origin.caller().clone()), (when, index))?; - Ok(()) - } - - /// Schedule a named task. - #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] - pub fn schedule_named( - origin: OriginFor, - id: TaskName, - when: BlockNumberFor, - maybe_periodic: Option>>, - priority: schedule::Priority, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule_named( - id, - DispatchTime::At(when), - maybe_periodic, - priority, - origin.caller().clone(), - T::Preimages::bound(*call)?, - )?; - Ok(()) - } - - /// Cancel a named scheduled task. - #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] - pub fn cancel_named(origin: OriginFor, id: TaskName) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_cancel_named(Some(origin.caller().clone()), id)?; - Ok(()) - } - - /// Anonymously schedule a task after a delay. - #[pallet::call_index(4)] - #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] - pub fn schedule_after( - origin: OriginFor, - after: BlockNumberFor, - maybe_periodic: Option>>, - priority: schedule::Priority, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule( - DispatchTime::After(after), - maybe_periodic, - priority, - origin.caller().clone(), - T::Preimages::bound(*call)?, - )?; - Ok(()) - } - - /// Schedule a named task after a delay. - #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] - pub fn schedule_named_after( - origin: OriginFor, - id: TaskName, - after: BlockNumberFor, - maybe_periodic: Option>>, - priority: schedule::Priority, - call: Box<::RuntimeCall>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule_named( - id, - DispatchTime::After(after), - maybe_periodic, - priority, - origin.caller().clone(), - T::Preimages::bound(*call)?, - )?; - Ok(()) - } - - /// Anonymously schedule a timelocked task. - #[pallet::call_index(6)] - #[pallet::weight(::WeightInfo::schedule_sealed(T::MaxScheduledPerBlock::get()))] - pub fn schedule_sealed( - origin: OriginFor, - when: BlockNumberFor, - priority: schedule::Priority, - ciphertext: Ciphertext, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule_sealed( - DispatchTime::At(when), - priority, - origin.caller().clone(), - ciphertext, - )?; - Ok(()) - } - } -} - -impl Pallet { - /// Helper to migrate scheduler when the pallet origin type has changed. - pub fn migrate_origin + codec::Decode>() { - Agenda::::translate::< - Vec< - Option< - Scheduled< - TaskName, - BoundedCallOf, - Ciphertext, - BlockNumberFor, - OldOrigin, - T::AccountId, - >, - >, - >, - _, - >(|_, agenda| { - Some(BoundedVec::truncate_from( - agenda - .into_iter() - .map(|schedule| { - schedule.map(|schedule| Scheduled { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - maybe_call: schedule.maybe_call, - maybe_ciphertext: None, - maybe_periodic: schedule.maybe_periodic, - origin: schedule.origin.into(), - _phantom: Default::default(), - }) - }) - .collect::>(), - )) - }); - } - - fn resolve_time( - when: DispatchTime>, - ) -> Result, DispatchError> { - let now = frame_system::Pallet::::block_number(); - - let when = match when { - DispatchTime::At(x) => x, - // The current block has already completed it's scheduled tasks, so - // Schedule the task at lest one block after this current block. - DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()), - }; - - if when <= now { - return Err(Error::::TargetBlockNumberInPast.into()); - } - - Ok(when) - } - - #[allow(clippy::result_large_err)] - fn place_task( - when: BlockNumberFor, - what: ScheduledOf, - ) -> Result>, (DispatchError, ScheduledOf)> { - let maybe_name = what.maybe_id; - let index = Self::push_to_agenda(when, what)?; - let address = (when, index); - if let Some(name) = maybe_name { - Lookup::::insert(name, address) - } - Self::deposit_event(Event::Scheduled { when: address.0, index: address.1 }); - Ok(address) - } - - #[allow(clippy::result_large_err)] - fn push_to_agenda( - when: BlockNumberFor, - what: ScheduledOf, - ) -> Result)> { - let mut agenda = Agenda::::get(when); - let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() { - // will always succeed due to the above check. - let _ = agenda.try_push(Some(what)); - agenda.len() as u32 - 1 - } else if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) { - agenda[hole_index] = Some(what); - hole_index as u32 - } else { - return Err((DispatchError::Exhausted, what)); - }; - Agenda::::insert(when, agenda); - Ok(index) - } - - /// Remove trailing `None` items of an agenda at `when`. If all items are `None` remove the - /// agenda record entirely. - fn cleanup_agenda(when: BlockNumberFor) { - let mut agenda = Agenda::::get(when); - match agenda.iter().rposition(|i| i.is_some()) { - Some(i) if agenda.len() > i + 1 => { - agenda.truncate(i + 1); - Agenda::::insert(when, agenda); - }, - Some(_) => {}, - None => { - Agenda::::remove(when); - }, - } - } - - fn do_schedule( - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: BoundedCallOf, - ) -> Result>, DispatchError> { - let when = Self::resolve_time(when)?; - - let lookup_hash = call.lookup_hash(); - - // sanitize maybe_periodic - let maybe_periodic = maybe_periodic - .filter(|p| p.1 > 1 && !p.0.is_zero()) - // Remove one from the number of repetitions since we will schedule one now. - .map(|(p, c)| (p, c - 1)); - let task = Scheduled { - maybe_id: None, - priority, - maybe_call: Some(call), - maybe_ciphertext: None, - maybe_periodic, - origin, - _phantom: PhantomData, - }; - let res = Self::place_task(when, task).map_err(|x| x.0)?; - - if let Some(hash) = lookup_hash { - // Request the call to be made available. - T::Preimages::request(&hash); - } - - Ok(res) - } - - fn do_cancel( - origin: Option, - (when, index): TaskAddress>, - ) -> Result<(), DispatchError> { - let scheduled = Agenda::::try_mutate(when, |agenda| { - agenda.get_mut(index as usize).map_or( - Ok(None), - |s| -> Result>, DispatchError> { - if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if matches!( - T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), - Some(Ordering::Less) | None - ) { - return Err(BadOrigin.into()); - } - }; - Ok(s.take()) - }, - ) - })?; - if let Some(s) = scheduled { - if s.maybe_ciphertext.is_none() && s.maybe_call.is_some() { - T::Preimages::drop(&s.maybe_call.clone().unwrap()); - } - - if let Some(id) = s.maybe_id { - Lookup::::remove(id); - } - Self::cleanup_agenda(when); - Self::deposit_event(Event::Canceled { when, index }); - Ok(()) - } else { - Err(Error::::NotFound.into()) - } - } - - fn do_reschedule( - (when, index): TaskAddress>, - new_time: DispatchTime>, - ) -> Result>, DispatchError> { - let new_time = Self::resolve_time(new_time)?; - - if new_time == when { - return Err(Error::::RescheduleNoChange.into()); - } - - let task = Agenda::::try_mutate(when, |agenda| { - let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - ensure!(!matches!(task, Some(Scheduled { maybe_id: Some(_), .. })), Error::::Named); - task.take().ok_or(Error::::NotFound) - })?; - Self::cleanup_agenda(when); - Self::deposit_event(Event::Canceled { when, index }); - - Self::place_task(new_time, task).map_err(|x| x.0) - } - - fn do_schedule_named( - id: TaskName, - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: BoundedCallOf, - ) -> Result>, DispatchError> { - // ensure id it is unique - if Lookup::::contains_key(id) { - return Err(Error::::FailedToSchedule.into()); - } - - let when = Self::resolve_time(when)?; - - let lookup_hash = call.lookup_hash(); - - // sanitize maybe_periodic - let maybe_periodic = maybe_periodic - .filter(|p| p.1 > 1 && !p.0.is_zero()) - // Remove one from the number of repetitions since we will schedule one now. - .map(|(p, c)| (p, c - 1)); - - let task = Scheduled { - maybe_id: Some(id), - priority, - maybe_call: Some(call), - maybe_ciphertext: None, - maybe_periodic, - origin, - _phantom: Default::default(), - }; - let res = Self::place_task(when, task).map_err(|x| x.0)?; - - if let Some(hash) = lookup_hash { - // Request the call to be made available. - T::Preimages::request(&hash); - } - - Ok(res) - } - - fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { - Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { - if let Some((when, index)) = lookup.take() { - let i = index as usize; - Agenda::::try_mutate(when, |agenda| -> DispatchResult { - if let Some(s) = agenda.get_mut(i) { - if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { - if matches!( - T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), - Some(Ordering::Less) | None - ) { - return Err(BadOrigin.into()); - } - T::Preimages::drop(&s.maybe_call.clone().unwrap()); - } - *s = None; - } - Ok(()) - })?; - Self::cleanup_agenda(when); - Self::deposit_event(Event::Canceled { when, index }); - Ok(()) - } else { - Err(Error::::NotFound.into()) - } - }) - } - - fn do_reschedule_named( - id: TaskName, - new_time: DispatchTime>, - ) -> Result>, DispatchError> { - let new_time = Self::resolve_time(new_time)?; - - let lookup = Lookup::::get(id); - let (when, index) = lookup.ok_or(Error::::NotFound)?; - - if new_time == when { - return Err(Error::::RescheduleNoChange.into()); - } - - let task = Agenda::::try_mutate(when, |agenda| { - let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - task.take().ok_or(Error::::NotFound) - })?; - Self::cleanup_agenda(when); - Self::deposit_event(Event::Canceled { when, index }); - Self::place_task(new_time, task).map_err(|x| x.0) - } - - /// schedule sealed tasks - fn do_schedule_sealed( - when: DispatchTime>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - ciphertext: Ciphertext, - ) -> Result>, DispatchError> { - let when = Self::resolve_time(when)?; - - let id = blake2_256(&ciphertext[..]); - - let task = Scheduled { - maybe_id: Some(id), - priority, - maybe_call: None, - maybe_ciphertext: Some(ciphertext), - maybe_periodic: None, - origin, - _phantom: PhantomData, - }; - let res = Self::place_task(when, task).map_err(|x| x.0)?; - Ok(res) - } -} - -enum ServiceTaskError { - /// Could not be executed due to missing preimage. - Unavailable, - /// Could not be executed due to weight limitations. - Overweight, -} -use ServiceTaskError::*; - -impl Pallet { - /// Service up to `max` agendas queue starting from earliest incompletely executed agenda. - fn service_agendas(weight: &mut WeightMeter, now: BlockNumberFor, max: u32) { - if weight.try_consume(T::WeightInfo::service_agendas_base()).is_err() { - return; - } - - let mut incomplete_since = now + One::one(); - let mut when = IncompleteSince::::take().unwrap_or(now); - let mut executed = 0; - - let max_items = T::MaxScheduledPerBlock::get(); - let mut count_down = max; - let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items); - while count_down > 0 && when <= now && weight.can_consume(service_agenda_base_weight) { - let then = T::TlockProvider::latest(); - if !Self::service_agenda(weight, &mut executed, now, when, then, u32::max_value()) { - incomplete_since = incomplete_since.min(when); - } - - when.saturating_inc(); - count_down.saturating_dec(); - } - incomplete_since = incomplete_since.min(when); - if incomplete_since <= now { - IncompleteSince::::put(incomplete_since); - } - } - - /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a - /// later block. - /// note: `then` is a latest block - fn service_agenda( - weight: &mut WeightMeter, - executed: &mut u32, - now: BlockNumberFor, - when: BlockNumberFor, - then: BlockNumberFor, - max: u32, - ) -> bool { - let mut agenda = Agenda::::get(when); - let mut ordered = agenda - .iter() - .enumerate() - .filter_map(|(index, maybe_item)| { - maybe_item.as_ref().map(|item| (index as u32, item.priority)) - }) - .collect::>(); - ordered.sort_by_key(|k| k.1); - let within_limit = weight - .try_consume(T::WeightInfo::service_agenda_base(ordered.len() as u32)) - .is_ok(); - debug_assert!(within_limit, "weight limit should have been checked in advance"); - - // Items which we know can be executed and have postponed for execution in a later block. - let mut postponed = (ordered.len() as u32).saturating_sub(max); - // Items which we don't know can ever be executed. - let mut dropped = 0; - - for (agenda_index, _) in ordered.into_iter().take(max as usize) { - let mut task = match agenda[agenda_index as usize].take() { - None => continue, - Some(t) => t, - }; - - if let Some(ref ciphertext) = task.maybe_ciphertext { - // the task should be delayed until `then` == `when` - if then == when { - task.maybe_call = T::TlockProvider::decrypt_at(&ciphertext.clone(), then) - .map_err(|_| pallet_randomness_beacon::TimelockError::DecryptionFailed) - .and_then(|bare| { - if let Ok(call) = - ::RuntimeCall::decode(&mut bare.message.as_slice()) - { - Ok(call) - } else { - Err(pallet_randomness_beacon::TimelockError::DecryptionFailed) - } - }) - .and_then(|call| { - T::Preimages::bound(call).map_err(|_| { - pallet_randomness_beacon::TimelockError::DecryptionFailed - }) - }) - .ok(); - } else { - // insert the task back into the agenda and continue - agenda[agenda_index as usize] = Some(task); - postponed += 1; - continue; - } - } - - // if we haven't dispatched the call and the call data is empty - // then there is no valid call, so ignore this task - if task.maybe_call.is_none() { - continue; - } - - let base_weight = T::WeightInfo::service_task( - // we know that maybe_call must be Some at this point - task.maybe_call.clone().unwrap().lookup_len().map(|x| x as usize), - task.maybe_id.is_some(), - task.maybe_periodic.is_some(), - ); - if !weight.can_consume(base_weight) { - postponed += 1; - break; - } - let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task); - agenda[agenda_index as usize] = match result { - Err((Unavailable, slot)) => { - dropped += 1; - slot - }, - Err((Overweight, slot)) => { - postponed += 1; - slot - }, - Ok(()) => { - *executed += 1; - None - }, - }; - } - if postponed > 0 || dropped > 0 { - Agenda::::insert(when, agenda); - } else { - Agenda::::remove(when); - } - - postponed == 0 - } - - /// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter. - /// - /// This involves: - /// - removing and potentially replacing the `Lookup` entry for the task. - /// - realizing the task's call which can include a preimage lookup. - /// - Rescheduling the task for execution in a later agenda if periodic. - #[allow(clippy::result_large_err)] - fn service_task( - weight: &mut WeightMeter, - now: BlockNumberFor, - when: BlockNumberFor, - agenda_index: u32, - is_first: bool, - mut task: ScheduledOf, - ) -> Result<(), (ServiceTaskError, Option>)> { - if let Some(ref id) = task.maybe_id { - Lookup::::remove(id); - } - - let (call, lookup_len) = match T::Preimages::peek(&task.maybe_call.clone().unwrap()) { - Ok(c) => c, - Err(_) => { - Self::deposit_event(Event::CallUnavailable { - task: (when, agenda_index), - id: task.maybe_id, - }); - - return Err((Unavailable, Some(task))); - }, - }; - - let _ = weight.try_consume(T::WeightInfo::service_task( - lookup_len.map(|x| x as usize), - task.maybe_id.is_some(), - task.maybe_periodic.is_some(), - )); - - match Self::execute_dispatch(weight, task.origin.clone(), call) { - Err(()) if is_first => { - T::Preimages::drop(&task.maybe_call.clone().unwrap()); - Self::deposit_event(Event::PermanentlyOverweight { - task: (when, agenda_index), - id: task.maybe_id, - }); - Err((Unavailable, Some(task))) - }, - Err(()) => Err((Overweight, Some(task))), - Ok(result) => { - Self::deposit_event(Event::Dispatched { - task: (when, agenda_index), - id: task.maybe_id, - result, - }); - if let &Some((period, count)) = &task.maybe_periodic { - if count > 1 { - task.maybe_periodic = Some((period, count - 1)); - } else { - task.maybe_periodic = None; - } - let wake = now.saturating_add(period); - match Self::place_task(wake, task) { - Ok(_) => {}, - Err((_, task)) => { - // TODO: Leave task in storage somewhere for it to be rescheduled - // manually. - T::Preimages::drop(&task.maybe_call.clone().unwrap()); - Self::deposit_event(Event::PeriodicFailed { - task: (when, agenda_index), - id: task.maybe_id, - }); - }, - } - } else { - T::Preimages::drop(&task.maybe_call.clone().unwrap()); - } - Ok(()) - }, - } - } - - /// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight` - /// counter does not exceed its limit and that it is counted accurately (e.g. accounted using - /// post info if available). - /// - /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the - /// call itself). - /// - /// Returns an error if the call is overweight. - fn execute_dispatch( - weight: &mut WeightMeter, - origin: T::PalletsOrigin, - call: ::RuntimeCall, - ) -> Result { - let base_weight = match origin.as_system_ref() { - Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(), - _ => T::WeightInfo::execute_dispatch_unsigned(), - }; - let call_weight = call.get_dispatch_info().weight; - // We only allow a scheduled call if it cannot push the weight past the limit. - let max_weight = base_weight.saturating_add(call_weight); - - if !weight.can_consume(max_weight) { - return Err(()); - } - - let dispatch_origin = origin.into(); - let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { - Ok(post_info) => (post_info.actual_weight, Ok(())), - Err(error_and_info) => - (error_and_info.post_info.actual_weight, Err(error_and_info.error)), - }; - let call_weight = maybe_actual_call_weight.unwrap_or(call_weight); - let _ = weight.try_consume(base_weight); - let _ = weight.try_consume(call_weight); - Ok(result) - } -} - -// TODO: handle `warning: use of deprecated trait `frame_support::traits::schedule::v2::Named`: -// Use `v3` instead. Will be removed after September 2024.` -// Then remove the `#[allow(warnings)]` attribute. -// https://github.com/ideal-lab5/idn-sdk/issues/63 -#[allow(warnings)] -impl schedule::v2::Anon, ::RuntimeCall, T::PalletsOrigin> - for Pallet -{ - type Address = TaskAddress>; - type Hash = T::Hash; - - fn schedule( - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: CallOrHashOf, - ) -> Result { - let call = call.as_value().ok_or(DispatchError::CannotLookup)?; - let call = T::Preimages::bound(call)?.transmute(); - Self::do_schedule(when, maybe_periodic, priority, origin, call) - } - - fn cancel((when, index): Self::Address) -> Result<(), ()> { - Self::do_cancel(None, (when, index)).map_err(|_| ()) - } - - fn reschedule( - address: Self::Address, - when: DispatchTime>, - ) -> Result { - Self::do_reschedule(address, when) - } - - fn next_dispatch_time((when, index): Self::Address) -> Result, ()> { - Agenda::::get(when).get(index as usize).ok_or(()).map(|_| when) - } -} - -// TODO: handle `warning: use of deprecated trait `frame_support::traits::schedule::v2::Named`: -// Use `v3` instead. Will be removed after September 2024.` -// Then remove the `#[allow(warnings)]` attribute. -// https://github.com/ideal-lab5/idn-sdk/issues/63 -#[allow(warnings)] -impl schedule::v2::Named, ::RuntimeCall, T::PalletsOrigin> - for Pallet -{ - type Address = TaskAddress>; - type Hash = T::Hash; - - fn schedule_named( - id: Vec, - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: CallOrHashOf, - ) -> Result { - let call = call.as_value().ok_or(())?; - let call = T::Preimages::bound(call).map_err(|_| ())?.transmute(); - let name = blake2_256(&id[..]); - Self::do_schedule_named(name, when, maybe_periodic, priority, origin, call).map_err(|_| ()) - } - - fn cancel_named(id: Vec) -> Result<(), ()> { - let name = blake2_256(&id[..]); - Self::do_cancel_named(None, name).map_err(|_| ()) - } - - fn reschedule_named( - id: Vec, - when: DispatchTime>, - ) -> Result { - let name = blake2_256(&id[..]); - Self::do_reschedule_named(name, when) - } - - fn next_dispatch_time(id: Vec) -> Result, ()> { - let name = blake2_256(&id[..]); - Lookup::::get(name) - .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) - .ok_or(()) - } -} - -impl schedule::v3::Anon, ::RuntimeCall, T::PalletsOrigin> - for Pallet -{ - type Address = TaskAddress>; - type Hasher = T::Hashing; - - fn schedule( - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: BoundedCallOf, - ) -> Result { - Self::do_schedule(when, maybe_periodic, priority, origin, call) - } - - fn cancel((when, index): Self::Address) -> Result<(), DispatchError> { - Self::do_cancel(None, (when, index)).map_err(map_err_to_v3_err::) - } - - fn reschedule( - address: Self::Address, - when: DispatchTime>, - ) -> Result { - Self::do_reschedule(address, when).map_err(map_err_to_v3_err::) - } - - fn next_dispatch_time( - (when, index): Self::Address, - ) -> Result, DispatchError> { - Agenda::::get(when) - .get(index as usize) - .ok_or(DispatchError::Unavailable) - .map(|_| when) - } -} - -use schedule::v3::TaskName; - -impl schedule::v3::Named, ::RuntimeCall, T::PalletsOrigin> - for Pallet -{ - type Address = TaskAddress>; - type Hasher = T::Hashing; - - fn schedule_named( - id: TaskName, - when: DispatchTime>, - maybe_periodic: Option>>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: BoundedCallOf, - ) -> Result { - Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call) - } - - fn cancel_named(id: TaskName) -> Result<(), DispatchError> { - Self::do_cancel_named(None, id).map_err(map_err_to_v3_err::) - } - - fn reschedule_named( - id: TaskName, - when: DispatchTime>, - ) -> Result { - Self::do_reschedule_named(id, when).map_err(map_err_to_v3_err::) - } - - fn next_dispatch_time(id: TaskName) -> Result, DispatchError> { - Lookup::::get(id) - .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) - .ok_or(DispatchError::Unavailable) - } -} - -/// Maps a pallet error to an `schedule::v3` error. -fn map_err_to_v3_err(err: DispatchError) -> DispatchError { - if err == DispatchError::from(Error::::NotFound) { - DispatchError::Unavailable - } else { - err - } -} diff --git a/pallets/scheduler/src/mock.rs b/pallets/scheduler/src/mock.rs deleted file mode 100644 index 4b34f2d..0000000 --- a/pallets/scheduler/src/mock.rs +++ /dev/null @@ -1,343 +0,0 @@ -// // This file is part of Substrate. - -// // Copyright (C) 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. - -// //! # Scheduler test environment. - -// use super::*; - -// use crate as scheduler; -// use frame_support::{ -// ord_parameter_types, parameter_types, -// traits::{ -// ConstU32, ConstU64, ConstBool, -// Contains, EitherOfDiverse, EqualPrivilegeOnly, -// OnFinalize, OnInitialize, -// }, -// weights::constants::RocksDbWeight, -// }; -// use frame_system::{EnsureRoot, EnsureSignedBy}; -// use sp_core::H256; -// use sp_runtime::{ -// traits::{BlakeTwo256, IdentityLookup}, -// BuildStorage, Perbill, -// }; -// use sp_consensus_etf_aura::sr25519::AuthorityId as AuraId; - -// use ark_bls12_381::{Fr, G2Affine as G2}; -// use etf_crypto_primitives::{ -// proofs::dleq::DLEQProof, -// ibe::fullident::BfIbe, -// client::etf_client::{DecryptionResult, DefaultEtfClient, EtfClient}, -// utils::hash_to_g1, -// }; - -// use pallet_etf::{TimelockError, TimelockEncryptionProvider}; -// use rand_chacha::{ -// ChaCha20Rng, -// rand_core::SeedableRng, -// }; - -// use ark_ec::AffineRepr; -// use ark_serialize::CanonicalSerialize; -// use ark_std::One as Won; -// type K = ark_bls12_381::G1Affine; - -// // Logger module to track execution. -// #[frame_support::pallet] -// pub mod logger { -// use super::{OriginCaller, OriginTrait}; -// use frame_support::{pallet_prelude::*, parameter_types}; -// use frame_system::pallet_prelude::*; - -// parameter_types! { -// static Log: Vec<(OriginCaller, u32)> = Vec::new(); -// } -// pub fn log() -> Vec<(OriginCaller, u32)> { -// Log::get().clone() -// } - -// #[pallet::pallet] -// pub struct Pallet(_); - -// #[pallet::hooks] -// impl Hooks> for Pallet {} - -// #[pallet::config] -// pub trait Config: frame_system::Config { -// type RuntimeEvent: From> + IsType<::RuntimeEvent>; -// } - -// #[pallet::event] -// #[pallet::generate_deposit(pub(super) fn deposit_event)] -// pub enum Event { -// Logged(u32, Weight), -// } - -// #[pallet::call] -// impl Pallet -// where -// ::RuntimeOrigin: OriginTrait, -// { -// #[pallet::call_index(0)] -// #[pallet::weight(*weight)] -// pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { -// Self::deposit_event(Event::Logged(i, weight)); -// Log::mutate(|log| { -// log.push((origin.caller().clone(), i)); -// }); -// Ok(()) -// } - -// #[pallet::call_index(1)] -// #[pallet::weight(*weight)] -// pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { -// Self::deposit_event(Event::Logged(i, weight)); -// Log::mutate(|log| { -// log.push((origin.caller().clone(), i)); -// }); -// Ok(()) -// } -// } -// } - -// type Block = frame_system::mocking::MockBlock; - -// frame_support::construct_runtime!( -// pub enum Test -// { -// System: frame_system::{Pallet, Call, Config, Storage, Event}, -// Logger: logger::{Pallet, Call, Event}, -// Scheduler: scheduler::{Pallet, Call, Storage, Event}, -// Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason}, -// RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, -// Aura: pallet_etf_aura, -// Etf: pallet_etf, -// } -// ); - -// // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. -// pub struct BaseFilter; -// impl Contains for BaseFilter { -// fn contains(call: &RuntimeCall) -> bool { -// !matches!(call, RuntimeCall::Logger(LoggerCall::log { .. })) -// } -// } - -// parameter_types! { -// pub BlockWeights: frame_system::limits::BlockWeights = -// frame_system::limits::BlockWeights::simple_max( -// Weight::from_parts(2_000_000_000_000, u64::MAX), -// ); -// } -// impl system::Config for Test { -// type BaseCallFilter = BaseFilter; -// type BlockWeights = BlockWeights; -// type BlockLength = (); -// type DbWeight = RocksDbWeight; -// type RuntimeOrigin = RuntimeOrigin; -// type RuntimeCall = RuntimeCall; -// type Nonce = u64; -// type Hash = H256; -// type Hashing = BlakeTwo256; -// type AccountId = u64; -// type Lookup = IdentityLookup; -// type Block = Block; -// type RuntimeEvent = RuntimeEvent; -// type BlockHashCount = ConstU64<250>; -// type Version = (); -// type PalletInfo = PalletInfo; -// type AccountData = (); -// type OnNewAccount = (); -// type OnKilledAccount = (); -// type SystemWeightInfo = (); -// type SS58Prefix = (); -// type OnSetCode = (); -// type MaxConsumers = ConstU32<16>; -// } - -// impl logger::Config for Test { -// type RuntimeEvent = RuntimeEvent; -// } -// ord_parameter_types! { -// pub const One: u64 = 1; -// } - -// impl pallet_preimage::Config for Test { -// type RuntimeEvent = RuntimeEvent; -// type WeightInfo = (); -// type Currency = (); -// type ManagerOrigin = EnsureRoot; -// type Consideration = (); -// } - -// impl pallet_timestamp::Config for Test { -// /// A timestamp: milliseconds since the unix epoch. -// type Moment = u64; -// type OnTimestampSet = (); -// type MinimumPeriod = ConstU64<{ 6000 / 2 }>; -// type WeightInfo = (); -// } - -// impl pallet_etf_aura::Config for Test { -// type AuthorityId = AuraId; -// type DisabledValidators = (); -// type MaxAuthorities = ConstU32<32>; -// type AllowMultipleBlocksPerSlot = ConstBool; - -// #[cfg(feature = "experimental")] -// type SlotDuration = pallet_etf_aura::MinimumPeriodTimesTwo; -// } - -// impl pallet_insecure_randomness_collective_flip::Config for Test {} - -// impl pallet_etf::Config for Test { -// type RuntimeEvent = RuntimeEvent; -// type WeightInfo = pallet_etf::weights::SubstrateWeightInfo; -// type Randomness = RandomnessCollectiveFlip; -// type SlotSecretProvider = Aura; -// } - -// pub struct TestWeightInfo; -// impl WeightInfo for TestWeightInfo { -// fn service_agendas_base() -> Weight { -// Weight::from_parts(0b0000_0001, 0) -// } -// fn service_agenda_base(i: u32) -> Weight { -// Weight::from_parts((i << 8) as u64 + 0b0000_0010, 0) -// } -// fn service_task_base() -> Weight { -// Weight::from_parts(0b0000_0100, 0) -// } -// fn service_task_periodic() -> Weight { -// Weight::from_parts(0b0000_1100, 0) -// } -// fn service_task_named() -> Weight { -// Weight::from_parts(0b0001_0100, 0) -// } -// fn service_task_fetched(s: u32) -> Weight { -// Weight::from_parts((s << 8) as u64 + 0b0010_0100, 0) -// } -// fn execute_dispatch_signed() -> Weight { -// Weight::from_parts(0b0100_0000, 0) -// } -// fn execute_dispatch_unsigned() -> Weight { -// Weight::from_parts(0b1000_0000, 0) -// } -// fn schedule(_s: u32) -> Weight { -// Weight::from_parts(50, 0) -// } -// fn cancel(_s: u32) -> Weight { -// Weight::from_parts(50, 0) -// } -// fn schedule_named(_s: u32) -> Weight { -// Weight::from_parts(50, 0) -// } -// fn cancel_named(_s: u32) -> Weight { -// Weight::from_parts(50, 0) -// } -// } -// parameter_types! { -// pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * -// BlockWeights::get().max_block; -// } - -// impl Config for Test { -// type RuntimeEvent = RuntimeEvent; -// type RuntimeOrigin = RuntimeOrigin; -// type PalletsOrigin = OriginCaller; -// type RuntimeCall = RuntimeCall; -// type MaximumWeight = MaximumSchedulerWeight; -// type ScheduleOrigin = EitherOfDiverse, EnsureSignedBy>; -// type MaxScheduledPerBlock = ConstU32<10>; -// type WeightInfo = TestWeightInfo; -// type OriginPrivilegeCmp = EqualPrivilegeOnly; -// type Preimages = Preimage; -// type TlockProvider = MockTlockProvider; -// } - -// pub type LoggerCall = logger::Call; - -// pub fn new_test_ext() -> sp_io::TestExternalities { -// let t = system::GenesisConfig::::default().build_storage().unwrap(); -// t.into() -// } - -// pub fn run_to_block(n: u64) { -// while System::block_number() < n { -// Scheduler::on_finalize(System::block_number()); -// System::set_block_number(System::block_number() + 1); -// Scheduler::on_initialize(System::block_number()); -// } -// } - -// pub fn convert_to_bytes(k: E) -> [u8;N] { -// let mut out = Vec::with_capacity(k.compressed_size()); -// k.serialize_compressed(&mut out).unwrap_or(()); -// let o: [u8; N] = out.try_into().unwrap_or([0;N]); -// o -// } - -// pub fn root() -> OriginCaller { -// system::RawOrigin::Root.into() -// } - -// // pub struct MockSlotSecretProvider; - -// // impl pallet_etf_aura::SlotSecretProvider for MockSlotSecretProvider { -// // fn get() -> Option { -// // let sk = Fr::one(); -// // let id = 4u64.to_string().as_bytes().to_vec(); -// // let pk = hash_to_g1(&id); -// // let generator: K = K::generator(); -// // let mut rng = ChaCha20Rng::seed_from_u64(4u64); -// // let proof = DLEQProof::new(sk, pk, generator, id, &mut rng); -// // let sk = convert_to_bytes::(proof.secret_commitment_g) -// // .try_into() -// // .expect("The slot secret should be valid; qed;"); -// // Some(sk.to_vec()) -// // } -// // } - -// pub struct MockTlockProvider; - -// impl TimelockEncryptionProvider for MockTlockProvider { -// // decrypts at block number 4 -// fn decrypt_current(ciphertext: Ciphertext) -> Result { -// let sk = Fr::one(); -// let id = 4u64.to_string().as_bytes().to_vec(); -// let pk = hash_to_g1(&id); -// let generator: K = K::generator(); -// let mut rng = ChaCha20Rng::seed_from_u64(4u64); -// let proof = DLEQProof::new(sk, pk, generator, id, &mut rng); -// let sk: [u8;48] = convert_to_bytes::(proof.secret_commitment_g) -// .try_into() -// .expect("The slot secret should be valid; qed;"); - -// let ibe_pp_bytes: [u8;96] = convert_to_bytes::(G2::generator()) -// .try_into() -// .expect("The slot secret should be valid; qed;"); - -// let pt = DefaultEtfClient::::decrypt( -// ibe_pp_bytes.to_vec(), -// ciphertext.ciphertext.to_vec(), -// ciphertext.nonce.to_vec(), -// vec![ciphertext.capsule.to_vec()], -// vec![sk.to_vec()], -// ).map_err(|_| TimelockError::DecryptionFailed)?; -// Ok(pt) -// } -// } diff --git a/pallets/scheduler/src/tests.rs b/pallets/scheduler/src/tests.rs deleted file mode 100644 index 241328a..0000000 --- a/pallets/scheduler/src/tests.rs +++ /dev/null @@ -1,2123 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Scheduler tests. - -use super::*; -use crate::mock::{ - logger, new_test_ext, root, run_to_block, LoggerCall, Preimage, RuntimeCall, Scheduler, Test, *, -}; -use frame_support::{ - assert_err, assert_noop, assert_ok, - traits::{ConstU32, Contains, OnInitialize, QueryPreimage, StorePreimage}, - Hashable, -}; -use sp_runtime::traits::Hash; -use substrate_test_utils::assert_eq_uvec; - -use ark_bls12_381::{Fr, G2Projective as G2}; -use ark_ec::Group; -use ark_std::{ops::Mul, rand::SeedableRng, One}; -use etf_crypto_primitives::{ - client::etf_client::{DefaultEtfClient, EtfClient}, - ibe::fullident::BfIbe, - utils::convert_to_bytes, -}; -use rand_chacha::ChaCha20Rng; - -#[test] -#[docify::export] -fn basic_scheduling_works() { - new_test_ext().execute_with(|| { - // Call to schedule - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // BaseCallFilter should be implemented to accept `Logger::log` runtime call which is - // implemented for `BaseFilter` in the mock runtime - assert!(!::BaseCallFilter::contains(&call)); - - // Schedule call to be executed at the 4th block - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap() - )); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - run_to_block(4); - // `log` runtime call should have executed at block 4 - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -#[docify::export] -fn scheduling_with_preimages_works() { - new_test_ext().execute_with(|| { - // Call to schedule - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - let hash = ::Hashing::hash_of(&call); - let len = call.using_encoded(|x| x.len()) as u32; - - // Important to use here `Bounded::Lookup` to ensure that that the Scheduler can request the - // hash from PreImage to dispatch the call - let hashed = Bounded::Lookup { hash, len }; - - // Schedule call to be executed at block 4 with the PreImage hash - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); - - // Register preimage on chain - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); - assert!(Preimage::is_requested(&hash)); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - run_to_block(4); - // preimage should not have been removed when executed by the scheduler - assert!(!Preimage::len(&hash).is_some()); - assert!(!Preimage::is_requested(&hash)); - // `log` runtime call should have executed at block 4 - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn schedule_after_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - assert!(!::BaseCallFilter::contains(&call)); - // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule( - DispatchTime::After(3), - None, - 127, - root(), - Preimage::bound(call).unwrap() - )); - run_to_block(5); - assert!(logger::log().is_empty()); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn schedule_after_zero_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule( - DispatchTime::After(0), - None, - 127, - root(), - Preimage::bound(call).unwrap() - )); - // Will trigger on the next block. - run_to_block(3); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Preimage::bound(RuntimeCall::Logger(logger::Call::log { - i: 42, - weight: Weight::from_parts(10, 0) - })) - .unwrap() - )); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(7); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); -} - -#[test] -fn reschedule_works() { - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap() - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0)); - - assert_noop!( - Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn reschedule_named_works() { - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); - - assert_noop!( - Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn reschedule_named_perodic_works() { - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(5)).unwrap(), (5, 0)); - assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); - - run_to_block(5); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - assert_eq!( - Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(10)).unwrap(), - (10, 0) - ); - - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - - run_to_block(13); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); -} - -#[test] -fn cancel_named_scheduling_works_with_normal_cancel() { - new_test_ext().execute_with(|| { - // at #4. - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })) - .unwrap(), - ) - .unwrap(); - let i = Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })) - .unwrap(), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); - assert_ok!(Scheduler::do_cancel(None, i)); - run_to_block(100); - assert!(logger::log().is_empty()); - }); -} - -#[test] -fn cancel_named_periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })) - .unwrap(), - ) - .unwrap(); - // same id results in error. - assert!(Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0) - })) - .unwrap(), - ) - .is_err()); - // different id is ok. - Scheduler::do_schedule_named( - [2u8; 32], - DispatchTime::At(8), - None, - 127, - root(), - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })) - .unwrap(), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); -} - -#[test] -fn scheduler_respects_weight_limits() { - let max_weight: Weight = ::MaximumWeight::get(); - new_test_ext().execute_with(|| { - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - )); - // 69 and 42 do not fit together - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); -} - -/// Permanently overweight calls are not deleted but also not executed. -#[test] -fn scheduler_does_not_delete_permanently_overweight_call() { - let max_weight: Weight = ::MaximumWeight::get(); - new_test_ext().execute_with(|| { - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - )); - // Never executes. - run_to_block(100); - assert_eq!(logger::log(), vec![]); - - // Assert the `PermanentlyOverweight` event. - assert_eq!( - System::events().last().unwrap().event, - crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(), - ); - // The call is still in the agenda. - assert!(Agenda::::get(4)[0].is_some()); - }); -} - -#[test] -fn scheduler_handles_periodic_failure() { - let max_weight: Weight = ::MaximumWeight::get(); - let max_per_block = ::MaxScheduledPerBlock::get(); - - new_test_ext().execute_with(|| { - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); - let bound = Preimage::bound(call).unwrap(); - - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - Some((4, u32::MAX)), - 127, - root(), - bound.clone(), - )); - // Executes 5 times till block 20. - run_to_block(20); - assert_eq!(logger::log().len(), 5); - - // Block 28 will already be full. - for _ in 0..max_per_block { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(28), - None, - 120, - root(), - bound.clone(), - )); - } - - // Going to block 24 will emit a `PeriodicFailed` event. - run_to_block(24); - assert_eq!(logger::log().len(), 6); - - assert_eq!( - System::events().last().unwrap().event, - crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(), - ); - }); -} - -#[test] -fn scheduler_handles_periodic_unavailable_preimage() { - let max_weight: Weight = ::MaximumWeight::get(); - - new_test_ext().execute_with(|| { - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); - let hash = ::Hashing::hash_of(&call); - let len = call.using_encoded(|x| x.len()) as u32; - // Important to use here `Bounded::Lookup` to ensure that we request the hash. - let bound = Bounded::Lookup { hash, len }; - // The preimage isn't requested yet. - assert!(!Preimage::is_requested(&hash)); - - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - Some((4, u32::MAX)), - 127, - root(), - bound.clone(), - )); - - // The preimage is requested. - assert!(Preimage::is_requested(&hash)); - - // Note the preimage. - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), call.encode())); - - // Executes 1 times till block 4. - run_to_block(4); - assert_eq!(logger::log().len(), 1); - - // Unnote the preimage - Preimage::unnote(&hash); - - // Does not ever execute again. - run_to_block(100); - assert_eq!(logger::log().len(), 1); - - // The preimage is not requested anymore. - assert!(!Preimage::is_requested(&hash)); - }); -} - -#[test] -fn scheduler_respects_priority_ordering() { - let max_weight: Weight = ::MaximumWeight::get(); - new_test_ext().execute_with(|| { - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 1, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Preimage::bound(call).unwrap(), - )); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); - }); -} - -#[test] -fn scheduler_respects_priority_ordering_with_soft_deadlines() { - new_test_ext().execute_with(|| { - let max_weight: Weight = ::MaximumWeight::get(); - let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 255, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 }); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 126, - root(), - Preimage::bound(call).unwrap(), - )); - - // 2600 does not fit with 69 or 42, but has higher priority, so will go through - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - // 69 and 42 fit together - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - }); -} - -#[test] -fn on_initialize_weight_is_correct() { - new_test_ext().execute_with(|| { - let call_weight = Weight::from_parts(25, 0); - - // Named - let call = RuntimeCall::Logger(LoggerCall::log { - i: 3, - weight: call_weight + Weight::from_parts(1, 0), - }); - assert_ok!(Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(3), - None, - 255, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: call_weight + Weight::from_parts(2, 0), - }); - // Anon Periodic - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(2), - Some((1000, 3)), - 128, - root(), - Preimage::bound(call).unwrap(), - )); - let call = RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: call_weight + Weight::from_parts(3, 0), - }); - // Anon - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(2), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - )); - // Named Periodic - let call = RuntimeCall::Logger(LoggerCall::log { - i: 2600, - weight: call_weight + Weight::from_parts(4, 0), - }); - assert_ok!(Scheduler::do_schedule_named( - [2u8; 32], - DispatchTime::At(1), - Some((1000, 3)), - 126, - root(), - Preimage::bound(call).unwrap(), - )); - - // Will include the named periodic only - assert_eq!( - Scheduler::on_initialize(1), - TestWeightInfo::service_agendas_base() + - TestWeightInfo::service_agenda_base(1) + - ::service_task(None, true, true) + - TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_parts(4, 0) - ); - assert_eq!(IncompleteSince::::get(), None); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - - // Will include anon and anon periodic - assert_eq!( - Scheduler::on_initialize(2), - TestWeightInfo::service_agendas_base() + - TestWeightInfo::service_agenda_base(2) + - ::service_task(None, false, true) + - TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_parts(3, 0) + - ::service_task(None, false, false) + - TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_parts(2, 0) - ); - assert_eq!(IncompleteSince::::get(), None); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - - // Will include named only - assert_eq!( - Scheduler::on_initialize(3), - TestWeightInfo::service_agendas_base() + - TestWeightInfo::service_agenda_base(1) + - ::service_task(None, true, false) + - TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_parts(1, 0) - ); - assert_eq!(IncompleteSince::::get(), None); - assert_eq!( - logger::log(), - vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] - ); - - // Will contain none - let actual_weight = Scheduler::on_initialize(4); - assert_eq!( - actual_weight, - TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0) - ); - }); -} - -#[test] -fn root_calls_works() { - new_test_ext().execute_with(|| { - let call = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })); - let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })); - assert_ok!( - Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call,) - ); - assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call2)); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32])); - assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); -} - -#[test] -fn fails_to_schedule_task_in_the_past() { - new_test_ext().execute_with(|| { - run_to_block(3); - - let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })); - let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })); - let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })); - - assert_noop!( - Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, 127, call1), - Error::::TargetBlockNumberInPast, - ); - - assert_noop!( - Scheduler::schedule(RuntimeOrigin::root(), 2, None, 127, call2), - Error::::TargetBlockNumberInPast, - ); - - assert_noop!( - Scheduler::schedule(RuntimeOrigin::root(), 3, None, 127, call3), - Error::::TargetBlockNumberInPast, - ); - }); -} - -#[test] -fn should_use_origin() { - new_test_ext().execute_with(|| { - let call = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })); - let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - [1u8; 32], - 4, - None, - 127, - call, - )); - assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32])); - assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); -} - -#[test] -fn should_check_origin() { - new_test_ext().execute_with(|| { - let call = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })); - let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { - i: 42, - weight: Weight::from_parts(10, 0), - })); - assert_noop!( - Scheduler::schedule_named( - system::RawOrigin::Signed(2).into(), - [1u8; 32], - 4, - None, - 127, - call - ), - BadOrigin - ); - assert_noop!( - Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), - BadOrigin - ); - }); -} - -#[test] -fn should_check_origin_for_cancel() { - new_test_ext().execute_with(|| { - let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { - i: 69, - weight: Weight::from_parts(10, 0), - })); - let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { - i: 42, - weight: Weight::from_parts(10, 0), - })); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - [1u8; 32], - 4, - None, - 127, - call, - )); - assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]), - BadOrigin - ); - assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); - assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin); - assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); - run_to_block(5); - assert_eq!( - logger::log(), - vec![ - (system::RawOrigin::Signed(1).into(), 69u32), - (system::RawOrigin::Signed(1).into(), 42u32) - ] - ); - }); -} - -#[test] -fn test_migrate_origin() { - new_test_ext().execute_with(|| { - for i in 0..3u64 { - let k = i.twox_64_concat(); - let old: Vec< - Option< - Scheduled< - [u8; 32], - BoundedCallOf, - BoundedVec>, - u64, - u32, - u64, - >, - >, - > = vec![ - Some(Scheduled { - maybe_id: None, - priority: i as u8 + 10, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_parts(100, 0), - })) - .unwrap(), - ), - maybe_ciphertext: None, - origin: 3u32, - maybe_periodic: None, - _phantom: Default::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(blake2_256(&b"test"[..])), - priority: 123, - origin: 2u32, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0), - })) - .unwrap(), - ), - maybe_ciphertext: None, - maybe_periodic: Some((456u64, 10)), - _phantom: Default::default(), - }), - ]; - frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); - } - - impl Into for u32 { - fn into(self) -> OriginCaller { - match self { - 3u32 => system::RawOrigin::Root.into(), - 2u32 => system::RawOrigin::None.into(), - _ => unreachable!("test make no use of it"), - } - } - } - - Scheduler::migrate_origin::(); - - assert_eq_uvec!( - Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledOf:: { - maybe_id: None, - priority: 10, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_parts(100, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(blake2_256(&b"test"[..])), - priority: 123, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(Scheduled { - maybe_id: None, - priority: 11, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_parts(100, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(blake2_256(&b"test"[..])), - priority: 123, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(Scheduled { - maybe_id: None, - priority: 12, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_parts(100, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(blake2_256(&b"test"[..])), - priority: 123, - maybe_call: Some( - Preimage::bound(RuntimeCall::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_parts(10, 0) - })) - .unwrap() - ), - maybe_ciphertext: None, - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); - }); -} - -#[test] -fn postponed_named_task_cannot_be_rescheduled() { - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(1000, 0) }); - let hash = ::Hashing::hash_of(&call); - let len = call.using_encoded(|x| x.len()) as u32; - // Important to use here `Bounded::Lookup` to ensure that we request the hash. - let hashed = Bounded::Lookup { hash, len }; - let name: [u8; 32] = hash.as_ref().try_into().unwrap(); - - let address = Scheduler::do_schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - hashed.clone(), - ) - .unwrap(); - assert!(Preimage::is_requested(&hash)); - assert!(Lookup::::contains_key(name)); - - // Run to a very large block. - run_to_block(10); - // It was not executed. - assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); - // Postponing removes the lookup. - assert!(!Lookup::::contains_key(name)); - - // The agenda still contains the call. - let agenda = Agenda::::iter().collect::>(); - assert_eq!(agenda.len(), 1); - assert_eq!( - agenda[0].1, - vec![Some(Scheduled { - maybe_id: Some(name), - priority: 127, - maybe_call: Some(hashed), - maybe_ciphertext: None, - maybe_periodic: None, - origin: root().into(), - _phantom: Default::default(), - })] - ); - - // Finally add the preimage. - assert_ok!(Preimage::note(call.encode().into())); - run_to_block(1000); - // It did not execute. - assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); - - // Manually re-schedule the call by name does not work. - assert_err!( - Scheduler::do_reschedule_named(name, DispatchTime::At(1001)), - Error::::NotFound - ); - // Manually re-scheduling the call by address errors. - assert_err!( - Scheduler::do_reschedule(address, DispatchTime::At(1001)), - Error::::Named - ); - }); -} - -/// Using the scheduler as `v3::Anon` works. -#[test] -fn scheduler_v3_anon_basic_works() { - use frame_support::traits::schedule::v3::Anon; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // Schedule a call. - let _address = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - // Executes in block 4. - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - // ... but not again. - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn scheduler_v3_anon_cancel_works() { - use frame_support::traits::schedule::v3::Anon; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - - // Schedule a call. - let address = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - // Cancel the call. - assert_ok!(>::cancel(address)); - // It did not get executed. - run_to_block(100); - assert!(logger::log().is_empty()); - // Cannot cancel again. - assert_err!(>::cancel(address), DispatchError::Unavailable); - }); -} - -#[test] -fn scheduler_v3_anon_reschedule_works() { - use frame_support::traits::schedule::v3::Anon; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // Schedule a call. - let address = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - - // Cannot re-schedule into the same block. - assert_noop!( - >::reschedule(address, DispatchTime::At(4)), - Error::::RescheduleNoChange - ); - // Cannot re-schedule into the past. - assert_noop!( - >::reschedule(address, DispatchTime::At(3)), - Error::::TargetBlockNumberInPast - ); - // Re-schedule to block 5. - assert_ok!(>::reschedule(address, DispatchTime::At(5))); - // Scheduled for block 5. - run_to_block(4); - assert!(logger::log().is_empty()); - run_to_block(5); - // Does execute in block 5. - assert_eq!(logger::log(), vec![(root(), 42)]); - // Cannot re-schedule executed task. - assert_noop!( - >::reschedule(address, DispatchTime::At(10)), - DispatchError::Unavailable - ); - }); -} - -#[test] -fn scheduler_v3_anon_next_schedule_time_works() { - use frame_support::traits::schedule::v3::Anon; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - - // Schedule a call. - let address = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - - // Scheduled for block 4. - assert_eq!(>::next_dispatch_time(address), Ok(4)); - // Block 4 executes it. - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42)]); - - // It has no dispatch time anymore. - assert_noop!( - >::next_dispatch_time(address), - DispatchError::Unavailable - ); - }); -} - -/// Re-scheduling a task changes its next dispatch time. -#[test] -fn scheduler_v3_anon_reschedule_and_next_schedule_time_work() { - use frame_support::traits::schedule::v3::Anon; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - - // Schedule a call. - let old_address = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - - // Scheduled for block 4. - assert_eq!(>::next_dispatch_time(old_address), Ok(4)); - // Re-schedule to block 5. - let address = - >::reschedule(old_address, DispatchTime::At(5)).unwrap(); - assert!(address != old_address); - // Scheduled for block 5. - assert_eq!(>::next_dispatch_time(address), Ok(5)); - - // Block 4 does nothing. - run_to_block(4); - assert!(logger::log().is_empty()); - // Block 5 executes it. - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 42)]); - }); -} - -#[test] -fn scheduler_v3_anon_schedule_agenda_overflows() { - use frame_support::traits::schedule::v3::Anon; - let max: u32 = ::MaxScheduledPerBlock::get(); - - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - - // Schedule the maximal number allowed per block. - for _ in 0..max { - >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - } - - // One more time and it errors. - assert_noop!( - >::schedule(DispatchTime::At(4), None, 127, root(), bound,), - DispatchError::Exhausted - ); - - run_to_block(4); - // All scheduled calls are executed. - assert_eq!(logger::log().len() as u32, max); - }); -} - -/// Cancelling and scheduling does not overflow the agenda but fills holes. -#[test] -fn scheduler_v3_anon_cancel_and_schedule_fills_holes() { - use frame_support::traits::schedule::v3::Anon; - let max: u32 = ::MaxScheduledPerBlock::get(); - assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3"); - - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - let mut addrs = Vec::<_>::default(); - - // Schedule the maximal number allowed per block. - for _ in 0..max { - addrs.push( - >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(), - ); - } - // Cancel three of them. - for addr in addrs.into_iter().take(3) { - >::cancel(addr).unwrap(); - } - // Schedule three new ones. - for i in 0..3 { - let (_block, index) = >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - assert_eq!(i, index); - } - - run_to_block(4); - // Maximum number of calls are executed. - assert_eq!(logger::log().len() as u32, max); - }); -} - -/// Re-scheduling does not overflow the agenda but fills holes. -#[test] -fn scheduler_v3_anon_reschedule_fills_holes() { - use frame_support::traits::schedule::v3::Anon; - let max: u32 = ::MaxScheduledPerBlock::get(); - assert!(max > 3, "pre-condition: This test only makes sense for MaxScheduledPerBlock > 3"); - - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - let mut addrs = Vec::<_>::default(); - - // Schedule the maximal number allowed per block. - for _ in 0..max { - addrs.push( - >::schedule( - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(), - ); - } - let mut new_addrs = Vec::<_>::default(); - // Reversed last three elements of block 4. - let last_three = addrs.into_iter().rev().take(3).collect::>(); - // Re-schedule three of them to block 5. - for addr in last_three.iter().cloned() { - new_addrs - .push(>::reschedule(addr, DispatchTime::At(5)).unwrap()); - } - // Re-scheduling them back into block 3 should result in the same addrs. - for (old, want) in new_addrs.into_iter().zip(last_three.into_iter().rev()) { - let new = >::reschedule(old, DispatchTime::At(4)).unwrap(); - assert_eq!(new, want); - } - - run_to_block(4); - // Maximum number of calls are executed. - assert_eq!(logger::log().len() as u32, max); - }); -} - -/// The scheduler can be used as `v3::Named` trait. -#[test] -fn scheduler_v3_named_basic_works() { - use frame_support::traits::schedule::v3::Named; - - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let name = [1u8; 32]; - - // Schedule a call. - let _address = >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - // Executes in block 4. - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - // ... but not again. - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -/// A named task can be cancelled by its name. -#[test] -fn scheduler_v3_named_cancel_named_works() { - use frame_support::traits::schedule::v3::Named; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - let name = [1u8; 32]; - - // Schedule a call. - >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - // Cancel the call by name. - assert_ok!(>::cancel_named(name)); - // It did not get executed. - run_to_block(100); - assert!(logger::log().is_empty()); - // Cannot cancel again. - assert_noop!(>::cancel_named(name), DispatchError::Unavailable); - }); -} - -/// A named task can also be cancelled by its address. -#[test] -fn scheduler_v3_named_cancel_without_name_works() { - use frame_support::traits::schedule::v3::{Anon, Named}; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - let name = [1u8; 32]; - - // Schedule a call. - let address = >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - // Cancel the call by address. - assert_ok!(>::cancel(address)); - // It did not get executed. - run_to_block(100); - assert!(logger::log().is_empty()); - // Cannot cancel again. - assert_err!(>::cancel(address), DispatchError::Unavailable); - }); -} - -/// A named task can be re-scheduled by its name but not by its address. -#[test] -fn scheduler_v3_named_reschedule_named_works() { - use frame_support::traits::schedule::v3::{Anon, Named}; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let name = [1u8; 32]; - - // Schedule a call. - let address = >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - - // Cannot re-schedule by address. - assert_noop!( - >::reschedule(address, DispatchTime::At(10)), - Error::::Named, - ); - // Cannot re-schedule into the same block. - assert_noop!( - >::reschedule_named(name, DispatchTime::At(4)), - Error::::RescheduleNoChange - ); - // Cannot re-schedule into the past. - assert_noop!( - >::reschedule_named(name, DispatchTime::At(3)), - Error::::TargetBlockNumberInPast - ); - // Re-schedule to block 5. - assert_ok!(>::reschedule_named(name, DispatchTime::At(5))); - // Scheduled for block 5. - run_to_block(4); - assert!(logger::log().is_empty()); - run_to_block(5); - // Does execute in block 5. - assert_eq!(logger::log(), vec![(root(), 42)]); - // Cannot re-schedule executed task. - assert_noop!( - >::reschedule_named(name, DispatchTime::At(10)), - DispatchError::Unavailable - ); - // Also not by address. - assert_noop!( - >::reschedule(address, DispatchTime::At(10)), - DispatchError::Unavailable - ); - }); -} - -#[test] -fn scheduler_v3_named_next_schedule_time_works() { - use frame_support::traits::schedule::v3::{Anon, Named}; - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let bound = Preimage::bound(call).unwrap(); - let name = [1u8; 32]; - - // Schedule a call. - let address = >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - - run_to_block(3); - // Did not execute till block 3. - assert!(logger::log().is_empty()); - - // Scheduled for block 4. - assert_eq!(>::next_dispatch_time(name), Ok(4)); - // Also works by address. - assert_eq!(>::next_dispatch_time(address), Ok(4)); - // Block 4 executes it. - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42)]); - - // It has no dispatch time anymore. - assert_noop!( - >::next_dispatch_time(name), - DispatchError::Unavailable - ); - // Also not by address. - assert_noop!( - >::next_dispatch_time(address), - DispatchError::Unavailable - ); - }); -} - -#[test] -fn cancel_last_task_removes_agenda() { - new_test_ext().execute_with(|| { - let when = 4; - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let address = Scheduler::do_schedule( - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call.clone()).unwrap(), - ) - .unwrap(); - let address2 = Scheduler::do_schedule( - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - // two tasks at agenda. - assert!(Agenda::::get(when).len() == 2); - assert_ok!(Scheduler::do_cancel(None, address)); - // still two tasks at agenda, `None` and `Some`. - assert!(Agenda::::get(when).len() == 2); - // cancel last task from `when` agenda. - assert_ok!(Scheduler::do_cancel(None, address2)); - // if all tasks `None`, agenda fully removed. - assert!(Agenda::::get(when).len() == 0); - }); -} - -#[test] -fn cancel_named_last_task_removes_agenda() { - new_test_ext().execute_with(|| { - let when = 4; - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call.clone()).unwrap(), - ) - .unwrap(); - Scheduler::do_schedule_named( - [2u8; 32], - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - // two tasks at agenda. - assert!(Agenda::::get(when).len() == 2); - assert_ok!(Scheduler::do_cancel_named(None, [2u8; 32])); - // removes trailing `None` and leaves one task. - assert!(Agenda::::get(when).len() == 1); - // cancel last task from `when` agenda. - assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); - // if all tasks `None`, agenda fully removed. - assert!(Agenda::::get(when).len() == 0); - }); -} - -#[test] -fn reschedule_last_task_removes_agenda() { - new_test_ext().execute_with(|| { - let when = 4; - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let address = Scheduler::do_schedule( - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call.clone()).unwrap(), - ) - .unwrap(); - let address2 = Scheduler::do_schedule( - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - // two tasks at agenda. - assert!(Agenda::::get(when).len() == 2); - assert_ok!(Scheduler::do_cancel(None, address)); - // still two tasks at agenda, `None` and `Some`. - assert!(Agenda::::get(when).len() == 2); - // reschedule last task from `when` agenda. - assert_eq!( - Scheduler::do_reschedule(address2, DispatchTime::At(when + 1)).unwrap(), - (when + 1, 0) - ); - // if all tasks `None`, agenda fully removed. - assert!(Agenda::::get(when).len() == 0); - }); -} - -#[test] -fn reschedule_named_last_task_removes_agenda() { - new_test_ext().execute_with(|| { - let when = 4; - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - Scheduler::do_schedule_named( - [1u8; 32], - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call.clone()).unwrap(), - ) - .unwrap(); - Scheduler::do_schedule_named( - [2u8; 32], - DispatchTime::At(when), - None, - 127, - root(), - Preimage::bound(call).unwrap(), - ) - .unwrap(); - // two tasks at agenda. - assert!(Agenda::::get(when).len() == 2); - assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); - // still two tasks at agenda, `None` and `Some`. - assert!(Agenda::::get(when).len() == 2); - // reschedule last task from `when` agenda. - assert_eq!( - Scheduler::do_reschedule_named([2u8; 32], DispatchTime::At(when + 1)).unwrap(), - (when + 1, 0) - ); - // if all tasks `None`, agenda fully removed. - assert!(Agenda::::get(when).len() == 0); - }); -} - -/// Ensures that an unvailable call sends an event. -#[test] -fn unavailable_call_is_detected() { - use frame_support::traits::schedule::v3::Named; - - new_test_ext().execute_with(|| { - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - let hash = ::Hashing::hash_of(&call); - let len = call.using_encoded(|x| x.len()) as u32; - // Important to use here `Bounded::Lookup` to ensure that we request the hash. - let bound = Bounded::Lookup { hash, len }; - - let name = [1u8; 32]; - - // Schedule a call. - let _address = >::schedule_named( - name, - DispatchTime::At(4), - None, - 127, - root(), - bound.clone(), - ) - .unwrap(); - - // Ensure the preimage isn't available - assert!(!Preimage::have(&bound)); - - // Executes in block 4. - run_to_block(4); - - assert_eq!( - System::events().last().unwrap().event, - crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into() - ); - }); -} - -#[test] -#[docify::export] -fn timelock_basic_scheduling_works() { - let mut rng = ChaCha20Rng::from_seed([4; 32]); - - let ids = vec![4u64.to_string().as_bytes().to_vec()]; - let t = 1; - - let ibe_pp: G2 = G2::generator().into(); - let s = Fr::one(); - let p_pub: G2 = ibe_pp.mul(s).into(); - - let ibe_pp_bytes = convert_to_bytes::(ibe_pp); - let p_pub_bytes = convert_to_bytes::(p_pub); - - // Q: how can we mock the decryption trait so that we can d1o whatever? - // probably don't really need to perform decryption here? - new_test_ext().execute_with(|| { - let _ = Etf::set_ibe_params( - // RuntimeOrigin::root(), - &vec![], - &ibe_pp_bytes.into(), - &p_pub_bytes.into(), - ); - - // Call to schedule - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // // then we convert to bytes and encrypt the call - let ct: etf_crypto_primitives::client::etf_client::AesIbeCt = - DefaultEtfClient::::encrypt( - ibe_pp_bytes.to_vec(), - p_pub_bytes.to_vec(), - &call.encode(), - ids, - t, - &mut rng, - ) - .unwrap(); - - let mut bounded_ct: BoundedVec> = BoundedVec::new(); - ct.aes_ct.ciphertext.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_ct.try_insert(idx, *i); - }); - - let mut bounded_nonce: BoundedVec> = BoundedVec::new(); - ct.aes_ct.nonce.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_nonce.try_insert(idx, *i); - }); - - let mut bounded_capsule: BoundedVec> = BoundedVec::new(); - // assumes we only care about a single point in the future - ct.etf_ct[0].iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_capsule.try_insert(idx, *i); - }); - - let ciphertext = - Ciphertext { ciphertext: bounded_ct, nonce: bounded_nonce, capsule: bounded_capsule }; - - // Schedule call to be executed at the 4th block - assert_ok!(Scheduler::do_schedule_sealed(DispatchTime::At(4), 127, root(), ciphertext,)); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - run_to_block(4); - // `log` runtime call should have executed at block 4 - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -// TODO: ensure tx fees are properly charged? -#[test] -#[docify::export] -fn timelock_undecryptable_ciphertext_no_execution() { - let mut rng = ChaCha20Rng::from_seed([4; 32]); - - let bad_ids = vec![3u64.to_string().as_bytes().to_vec()]; - - let t = 1; - - let ibe_pp: G2 = G2::generator().into(); - let s = Fr::one(); - let p_pub: G2 = ibe_pp.mul(s).into(); - - let ibe_pp_bytes = convert_to_bytes::(ibe_pp); - let p_pub_bytes = convert_to_bytes::(p_pub); - - new_test_ext().execute_with(|| { - let _ = Etf::set_ibe_params( - // RuntimeOrigin::root(), - &vec![], - &ibe_pp_bytes.into(), - &p_pub_bytes.into(), - ); - - // Call to schedule - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // encrypts the ciphertext for the wrong identity - let ct: etf_crypto_primitives::client::etf_client::AesIbeCt = - DefaultEtfClient::::encrypt( - ibe_pp_bytes.to_vec(), - p_pub_bytes.to_vec(), - &call.encode(), - bad_ids, - t, - &mut rng, - ) - .unwrap(); - - let mut bounded_ct: BoundedVec> = BoundedVec::new(); - ct.aes_ct.ciphertext.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_ct.try_insert(idx, *i); - }); - - let mut bounded_nonce: BoundedVec> = BoundedVec::new(); - ct.aes_ct.nonce.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_nonce.try_insert(idx, *i); - }); - - let mut bounded_capsule: BoundedVec> = BoundedVec::new(); - // assumes we only care about a single point in the future - ct.etf_ct[0].iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_capsule.try_insert(idx, *i); - }); - - let ciphertext = - Ciphertext { ciphertext: bounded_ct, nonce: bounded_nonce, capsule: bounded_capsule }; - - // Schedule call to be executed at the 4th block - assert_ok!(Scheduler::do_schedule_sealed(DispatchTime::At(4), 127, root(), ciphertext,)); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - run_to_block(4); - // `log` runtime call should NOT have executed at block 4 - assert!(logger::log().is_empty()); - }); -} - -#[test] -#[docify::export] -fn timelock_undecodable_runtime_call_no_execution() { - let mut rng = ChaCha20Rng::from_seed([4; 32]); - - let ids = vec![4u64.to_string().as_bytes().to_vec()]; - let t = 1; - - let ibe_pp: G2 = G2::generator().into(); - let s = Fr::one(); - let p_pub: G2 = ibe_pp.mul(s).into(); - - let ibe_pp_bytes = convert_to_bytes::(ibe_pp); - let p_pub_bytes = convert_to_bytes::(p_pub); - - new_test_ext().execute_with(|| { - let _ = Etf::set_ibe_params( - // RuntimeOrigin::root(), - &vec![], - &ibe_pp_bytes.into(), - &p_pub_bytes.into(), - ); - - // Call to schedule - // let call = - // RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // encrypts the ciphertext for the wrong identity - let ct: etf_crypto_primitives::client::etf_client::AesIbeCt = - DefaultEtfClient::::encrypt( - ibe_pp_bytes.to_vec(), - p_pub_bytes.to_vec(), - &b"bad-call-data".encode(), - ids, - t, - &mut rng, - ) - .unwrap(); - - let mut bounded_ct: BoundedVec> = BoundedVec::new(); - ct.aes_ct.ciphertext.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_ct.try_insert(idx, *i); - }); - - let mut bounded_nonce: BoundedVec> = BoundedVec::new(); - ct.aes_ct.nonce.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_nonce.try_insert(idx, *i); - }); - - let mut bounded_capsule: BoundedVec> = BoundedVec::new(); - // assumes we only care about a single point in the future - ct.etf_ct[0].iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_capsule.try_insert(idx, *i); - }); - - let ciphertext = - Ciphertext { ciphertext: bounded_ct, nonce: bounded_nonce, capsule: bounded_capsule }; - - // Schedule call to be executed at the 4th block - assert_ok!(Scheduler::do_schedule_sealed(DispatchTime::At(4), 127, root(), ciphertext,)); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - run_to_block(4); - // `log` runtime call should NOT have executed at block 4 - assert!(logger::log().is_empty()); - }); -} - -#[test] -#[docify::export] -fn timelock_cancel_works() { - let mut rng = ChaCha20Rng::from_seed([4; 32]); - - let ids = vec![4u64.to_string().as_bytes().to_vec()]; - let t = 1; - - let ibe_pp: G2 = G2::generator().into(); - let s = Fr::one(); - let p_pub: G2 = ibe_pp.mul(s).into(); - - let ibe_pp_bytes = convert_to_bytes::(ibe_pp); - let p_pub_bytes = convert_to_bytes::(p_pub); - - // Q: how can we mock the decryption trait so that we can d1o whatever? - // probably don't really need to perform decryption here? - new_test_ext().execute_with(|| { - let _ = Etf::set_ibe_params( - // RuntimeOrigin::root(), - &vec![], - &ibe_pp_bytes.into(), - &p_pub_bytes.into(), - ); - - // Call to schedule - let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); - - // // then we convert to bytes and encrypt the call - let ct: etf_crypto_primitives::client::etf_client::AesIbeCt = - DefaultEtfClient::::encrypt( - ibe_pp_bytes.to_vec(), - p_pub_bytes.to_vec(), - &call.encode(), - ids, - t, - &mut rng, - ) - .unwrap(); - - let mut bounded_ct: BoundedVec> = BoundedVec::new(); - ct.aes_ct.ciphertext.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_ct.try_insert(idx, *i); - }); - - let mut bounded_nonce: BoundedVec> = BoundedVec::new(); - ct.aes_ct.nonce.iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_nonce.try_insert(idx, *i); - }); - - let mut bounded_capsule: BoundedVec> = BoundedVec::new(); - // assumes we only care about a single point in the future - ct.etf_ct[0].iter().enumerate().for_each(|(idx, i)| { - let _ = bounded_capsule.try_insert(idx, *i); - }); - - let ciphertext = - Ciphertext { ciphertext: bounded_ct, nonce: bounded_nonce, capsule: bounded_capsule }; - - // Schedule call to be executed at the 4th block - assert_ok!(Scheduler::do_schedule_sealed(DispatchTime::At(4), 127, root(), ciphertext,)); - - // `log` runtime call should not have executed yet - run_to_block(3); - assert!(logger::log().is_empty()); - - // now cancel - assert_ok!(Scheduler::do_cancel(None, (4, 0),)); - - run_to_block(4); - assert!(logger::log().is_empty()); - }); -} diff --git a/pallets/scheduler/src/weights.rs b/pallets/scheduler/src/weights.rs deleted file mode 100644 index 4301f3e..0000000 --- a/pallets/scheduler/src/weights.rs +++ /dev/null @@ -1,226 +0,0 @@ - -//! Autogenerated weights for `pallet_scheduler` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `DESKTOP-RN9BJOQ`, CPU: `Intel(R) Core(TM) i7-9700KF CPU @ 3.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/node -// benchmark -// pallet -// --chain -// dev -// --wasm-execution=compiled -// --pallet -// pallet_scheduler -// --extrinsic -// * -// --steps -// 50 -// --repeat -// 20 -// --output -// /home/driemworks/ideal/etf/pallets/scheduler/src/weights.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -pub trait WeightInfo { - fn service_agendas_base() -> Weight; - fn service_agenda_base(s: u32, ) -> Weight; - fn service_task_base() -> Weight; - fn service_task_fetched(s: u32, ) -> Weight; - fn service_task_named() -> Weight; - fn service_task_periodic() -> Weight; - fn execute_dispatch_signed() -> Weight; - fn execute_dispatch_unsigned() -> Weight; - fn schedule(s: u32, ) -> Weight; - fn cancel(s: u32, ) -> Weight; - fn schedule_named(s: u32, ) -> Weight; - fn cancel_named(s: u32, ) -> Weight; - fn schedule_sealed(s: u32, ) -> Weight; -} - -/// Weight functions for `pallet_scheduler`. -pub struct SubstrateWeightInfo(PhantomData); -impl WeightInfo for SubstrateWeightInfo { - /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) - /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn service_agendas_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `30` - // Estimated: `1489` - // Minimum execution time: 3_300_000 picoseconds. - Weight::from_parts(3_600_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 512]`. - fn service_agenda_base(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `80 + s * (179 ±0)` - // Estimated: `688023` - // Minimum execution time: 3_700_000 picoseconds. - Weight::from_parts(5_647_919, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 1_714 - .saturating_add(Weight::from_parts(451_248, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_300_000 picoseconds. - Weight::from_parts(4_600_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Preimage::PreimageFor` (r:1 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// The range of component `s` is `[128, 4194304]`. - fn service_task_fetched(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `142 + s * (1 ±0)` - // Estimated: `3607 + s * (1 ±0)` - // Minimum execution time: 18_400_000 picoseconds. - Weight::from_parts(19_000_000, 0) - .saturating_add(Weight::from_parts(0, 3607)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_353, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) - } - /// Storage: `Scheduler::Lookup` (r:0 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - fn service_task_named() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_200_000 picoseconds. - Weight::from_parts(6_800_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_periodic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_200_000 picoseconds. - Weight::from_parts(4_300_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_900_000 picoseconds. - Weight::from_parts(3_600_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_900_000 picoseconds. - Weight::from_parts(3_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 511]`. - fn schedule(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `80 + s * (179 ±0)` - // Estimated: `688023` - // Minimum execution time: 12_400_000 picoseconds. - Weight::from_parts(16_659_502, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 2_043 - .saturating_add(Weight::from_parts(499_707, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:0 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 512]`. - fn cancel(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `80 + s * (211 ±0)` - // Estimated: `688023` - // Minimum execution time: 17_500_000 picoseconds. - Weight::from_parts(18_086_329, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 2_193 - .saturating_add(Weight::from_parts(761_308, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Scheduler::Lookup` (r:1 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 511]`. - fn schedule_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `596 + s * (212 ±0)` - // Estimated: `688023` - // Minimum execution time: 16_200_000 picoseconds. - Weight::from_parts(25_244_435, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 2_427 - .saturating_add(Weight::from_parts(516_404, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Scheduler::Lookup` (r:1 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 512]`. - fn cancel_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `708 + s * (211 ±0)` - // Estimated: `688023` - // Minimum execution time: 19_300_000 picoseconds. - Weight::from_parts(28_488_805, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 2_631 - .saturating_add(Weight::from_parts(738_990, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(684558), added: 687033, mode: `MaxEncodedLen`) - /// The range of component `s` is `[0, 511]`. - fn schedule_sealed(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `80 + s * (211 ±0)` - // Estimated: `688023` - // Minimum execution time: 11_600_000 picoseconds. - Weight::from_parts(17_669_158, 0) - .saturating_add(Weight::from_parts(0, 688023)) - // Standard Error: 1_496 - .saturating_add(Weight::from_parts(483_707, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} From 65abd66147d7216efa2dce6adfe9eee970b25074 Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 10:51:40 -0600 Subject: [PATCH 4/7] remove pallets/etf, pallets/randomness-beacon, and primitives/consensus/beefy-etf --- Cargo.lock | 481 +------------- Cargo.toml | 4 +- pallets/etf/Cargo.toml | 88 --- pallets/etf/README.md | 3 - pallets/etf/src/lib.rs | 157 ----- pallets/etf/src/mock.rs | 61 -- pallets/etf/src/tests.rs | 35 - pallets/randomness-beacon/Cargo.toml | 95 --- pallets/randomness-beacon/README.md | 33 - pallets/randomness-beacon/src/lib.rs | 426 ------------- pallets/randomness-beacon/src/mock.rs | 207 ------ pallets/randomness-beacon/src/tests.rs | 192 ------ primitives/consensus/beefy-etf/Cargo.toml | 77 --- .../consensus/beefy-etf/src/commitment.rs | 526 --------------- primitives/consensus/beefy-etf/src/lib.rs | 600 ------------------ primitives/consensus/beefy-etf/src/mmr.rs | 265 -------- primitives/consensus/beefy-etf/src/payload.rs | 108 ---- .../consensus/beefy-etf/src/test_utils.rs | 222 ------- primitives/consensus/beefy-etf/src/witness.rs | 254 -------- .../beefy-etf/test-res/large-raw-commitment | Bin 44638 -> 0 bytes 20 files changed, 15 insertions(+), 3819 deletions(-) delete mode 100644 pallets/etf/Cargo.toml delete mode 100644 pallets/etf/README.md delete mode 100644 pallets/etf/src/lib.rs delete mode 100644 pallets/etf/src/mock.rs delete mode 100644 pallets/etf/src/tests.rs delete mode 100644 pallets/randomness-beacon/Cargo.toml delete mode 100644 pallets/randomness-beacon/README.md delete mode 100644 pallets/randomness-beacon/src/lib.rs delete mode 100644 pallets/randomness-beacon/src/mock.rs delete mode 100644 pallets/randomness-beacon/src/tests.rs delete mode 100644 primitives/consensus/beefy-etf/Cargo.toml delete mode 100644 primitives/consensus/beefy-etf/src/commitment.rs delete mode 100644 primitives/consensus/beefy-etf/src/lib.rs delete mode 100644 primitives/consensus/beefy-etf/src/mmr.rs delete mode 100644 primitives/consensus/beefy-etf/src/payload.rs delete mode 100644 primitives/consensus/beefy-etf/src/test_utils.rs delete mode 100644 primitives/consensus/beefy-etf/src/witness.rs delete mode 100644 primitives/consensus/beefy-etf/test-res/large-raw-commitment diff --git a/Cargo.lock b/Cargo.lock index bf46af2..2873921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,14 +895,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "binary-merkle-tree" -version = "13.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hash-db", -] - [[package]] name = "bitcoin-internals" version = "0.2.0" @@ -1834,40 +1826,15 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "frame-benchmarking" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-support-procedural 23.0.0", - "frame-system 28.0.0", - "linregress", - "log", - "parity-scale-codec", - "paste", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "static_assertions", -] - [[package]] name = "frame-benchmarking" version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01bdd47c2d541b38bd892da647d1e972c9d85b4ecd7094ad64f7600175da54d" dependencies = [ - "frame-support 38.2.0", - "frame-support-procedural 30.0.4", - "frame-system 38.0.0", + "frame-support", + "frame-support-procedural", + "frame-system", "linregress", "log", "parity-scale-codec", @@ -1884,34 +1851,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "frame-election-provider-solution-type" -version = "13.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "frame-election-provider-support" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-election-provider-solution-type", - "frame-support 28.0.0", - "frame-system 28.0.0", - "parity-scale-codec", - "scale-info", - "sp-arithmetic 23.0.0", - "sp-core 28.0.0", - "sp-npos-elections", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "frame-metadata" version = "16.0.0" @@ -1924,47 +1863,6 @@ dependencies = [ "serde", ] -[[package]] -name = "frame-support" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "aquamarine", - "array-bytes", - "bitflags 1.3.2", - "docify", - "environmental", - "frame-metadata", - "frame-support-procedural 23.0.0", - "impl-trait-for-tuples", - "k256", - "log", - "macro_magic", - "parity-scale-codec", - "paste", - "scale-info", - "serde", - "serde_json", - "smallvec", - "sp-api 26.0.0", - "sp-arithmetic 23.0.0", - "sp-core 28.0.0", - "sp-crypto-hashing-proc-macro 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-genesis-builder 0.8.0", - "sp-inherents 26.0.0", - "sp-io 30.0.0", - "sp-metadata-ir 0.6.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-weights 27.0.0", - "static_assertions", - "tt-call", -] - [[package]] name = "frame-support" version = "38.2.0" @@ -1977,7 +1875,7 @@ dependencies = [ "docify", "environmental", "frame-metadata", - "frame-support-procedural 30.0.4", + "frame-support-procedural", "impl-trait-for-tuples", "k256", "log", @@ -1993,12 +1891,12 @@ dependencies = [ "sp-core 34.0.0", "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-genesis-builder 0.15.1", - "sp-inherents 34.0.0", + "sp-genesis-builder", + "sp-inherents", "sp-io 38.0.0", "sp-metadata-ir 0.7.0", "sp-runtime 39.0.5", - "sp-staking 36.0.0", + "sp-staking", "sp-state-machine 0.43.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-tracing 17.0.1", @@ -2007,25 +1905,6 @@ dependencies = [ "tt-call", ] -[[package]] -name = "frame-support-procedural" -version = "23.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "Inflector", - "cfg-expr", - "derive-syn-parse", - "expander", - "frame-support-procedural-tools 10.0.0", - "itertools 0.11.0", - "macro_magic", - "proc-macro-warning", - "proc-macro2", - "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "syn 2.0.89", -] - [[package]] name = "frame-support-procedural" version = "30.0.4" @@ -2036,7 +1915,7 @@ dependencies = [ "cfg-expr", "derive-syn-parse", "expander", - "frame-support-procedural-tools 13.0.1", + "frame-support-procedural-tools", "itertools 0.11.0", "macro_magic", "proc-macro-warning", @@ -2046,41 +1925,19 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "frame-support-procedural-tools" -version = "10.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support-procedural-tools-derive 11.0.0", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "frame-support-procedural-tools" version = "13.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81a088fd6fda5f53ff0c17fc7551ce8bd0ead14ba742228443c8196296a7369b" dependencies = [ - "frame-support-procedural-tools-derive 12.0.0", + "frame-support-procedural-tools-derive", "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "frame-support-procedural-tools-derive" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "frame-support-procedural-tools-derive" version = "12.0.0" @@ -2092,26 +1949,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "frame-system" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "cfg-if", - "docify", - "frame-support 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-version 29.0.0", - "sp-weights 27.0.0", -] - [[package]] name = "frame-system" version = "38.0.0" @@ -2120,7 +1957,7 @@ checksum = "e3c7fa02f8c305496d2ae52edaecdb9d165f11afa965e05686d7d7dd1ce93611" dependencies = [ "cfg-if", "docify", - "frame-support 38.2.0", + "frame-support", "log", "parity-scale-codec", "scale-info", @@ -4023,36 +3860,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "pallet-authorship" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-system 28.0.0", - "impl-trait-for-tuples", - "parity-scale-codec", - "scale-info", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-balances" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "pallet-drand" version = "0.0.1" @@ -4065,9 +3872,9 @@ dependencies = [ "ark-scale 0.0.11", "ark-serialize", "ark-std", - "frame-benchmarking 38.0.0", - "frame-support 38.2.0", - "frame-system 38.0.0", + "frame-benchmarking", + "frame-support", + "frame-system", "hex", "log", "parity-scale-codec", @@ -4085,189 +3892,6 @@ dependencies = [ "w3f-bls", ] -[[package]] -name = "pallet-etf" -version = "28.0.0" -dependencies = [ - "ark-bls12-377", - "ark-serialize", - "ark-std", - "array-bytes", - "binary-merkle-tree", - "frame-election-provider-support", - "frame-support 28.0.0", - "frame-system 28.0.0", - "getrandom 0.2.15", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-mmr", - "pallet-offences", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "serde", - "sp-consensus-beefy-etf", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-mmr" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-mmr-primitives", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-offences" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "serde", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-randomness-beacon" -version = "1.0.0" -dependencies = [ - "ark-bls12-377", - "ark-ff", - "ark-serialize", - "ark-std", - "array-bytes", - "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", - "frame-election-provider-support", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-etf", - "pallet-mmr", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "serde", - "sha2 0.10.8", - "sha3", - "sp-consensus-beefy-etf", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "w3f-bls", -] - -[[package]] -name = "pallet-session" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-support 28.0.0", - "frame-system 28.0.0", - "impl-trait-for-tuples", - "log", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-session", - "sp-staking 26.0.0", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-trie 29.0.0", -] - -[[package]] -name = "pallet-staking" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-benchmarking 28.0.0", - "frame-election-provider-support", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-authorship", - "pallet-session", - "parity-scale-codec", - "scale-info", - "serde", - "sp-application-crypto 30.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - -[[package]] -name = "pallet-staking-reward-curve" -version = "11.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", -] - -[[package]] -name = "pallet-timestamp" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "frame-benchmarking 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "parity-scale-codec", - "scale-info", - "sp-inherents 26.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-timestamp", -] - [[package]] name = "parity-bip39" version = "2.0.1" @@ -5813,7 +5437,7 @@ dependencies = [ "scale-info", "serde", "sp-ark-bls12-381", - "sp-inherents 34.0.0", + "sp-inherents", ] [[package]] @@ -6042,18 +5666,6 @@ dependencies = [ "sp-storage 21.0.0", ] -[[package]] -name = "sp-genesis-builder" -version = "0.8.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde_json", - "sp-api 26.0.0", - "sp-runtime 31.0.1", -] - [[package]] name = "sp-genesis-builder" version = "0.15.1" @@ -6067,19 +5679,6 @@ dependencies = [ "sp-runtime 39.0.5", ] -[[package]] -name = "sp-inherents" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "impl-trait-for-tuples", - "parity-scale-codec", - "scale-info", - "sp-runtime 31.0.1", - "thiserror 1.0.69", -] - [[package]] name = "sp-inherents" version = "34.0.0" @@ -6220,19 +5819,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "sp-npos-elections" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde", - "sp-arithmetic 23.0.0", - "sp-core 28.0.0", - "sp-runtime 31.0.1", -] - [[package]] name = "sp-panic-handler" version = "13.0.0" @@ -6403,33 +5989,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-session" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "scale-info", - "sp-api 26.0.0", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", -] - -[[package]] -name = "sp-staking" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core 28.0.0", - "sp-runtime 31.0.1", -] - [[package]] name = "sp-staking" version = "36.0.0" @@ -6538,18 +6097,6 @@ dependencies = [ "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sp-timestamp" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "async-trait", - "parity-scale-codec", - "sp-inherents 26.0.0", - "sp-runtime 31.0.1", - "thiserror 1.0.69", -] - [[package]] name = "sp-tracing" version = "16.0.0" diff --git a/Cargo.toml b/Cargo.toml index 44652d7..8538c61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,7 @@ members = [ "client/consensus/randomness-beacon", "primitives/consensus/beefy-etf", "primitives/consensus/randomness-beacon", - "pallets/drand", - "pallets/etf", - "pallets/randomness-beacon", + "pallets/drand" ] resolver = "2" diff --git a/pallets/etf/Cargo.toml b/pallets/etf/Cargo.toml deleted file mode 100644 index 388d7fb..0000000 --- a/pallets/etf/Cargo.toml +++ /dev/null @@ -1,88 +0,0 @@ -[package] -name = "pallet-etf" -version = "28.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -repository.workspace = true -description = "BEEFY FRAME pallet" -homepage = "https://substrate.io" - -[lints] -workspace = true - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { optional = true, workspace = true, default-features = true } -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-authorship = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -ark-serialize = { version = "0.4.0", default-features = false } -ark-std = { version = "0.4.0", default-features = false } -ark-bls12-377 = { version = "0.4.0", features = ["curve"], default-features = false } -getrandom = { version = "0.2", features = ["js"] } - -[dev-dependencies] -frame-election-provider-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-balances = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-offences = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking-reward-curve = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-timestamp = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -array-bytes = "6.1" -binary-merkle-tree = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -[features] -default = ["std"] -std = [ - "ark-std/std", - "ark-serialize/std", - "ark-bls12-377/std", - "codec/std", - "frame-election-provider-support/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-offences/std", - "pallet-session/std", - "pallet-staking/std", - "pallet-timestamp/std", - "scale-info/std", - "serde/std", - "sp-consensus-beefy-etf/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-session/std", - "sp-staking/std", - "sp-state-machine/std", - "sp-std/std", -] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-offences/try-runtime", - "pallet-session/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/etf/README.md b/pallets/etf/README.md deleted file mode 100644 index b10764b..0000000 --- a/pallets/etf/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# pallet-etf - -This pallet is responsible for storing shares and commitments required to power the ETF post finality gadget. Specifically, the data contained in this pallet allows the ETF authorities to derive session keys which they use to produce thereshold BLS sigs. \ No newline at end of file diff --git a/pallets/etf/src/lib.rs b/pallets/etf/src/lib.rs deleted file mode 100644 index 714737d..0000000 --- a/pallets/etf/src/lib.rs +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -#![cfg_attr(not(feature = "std"), no_std)] -use codec::MaxEncodedLen; - -use frame_support::{pallet_prelude::*, traits::Get, BoundedVec, Parameter}; -use sp_runtime::traits::Member; -use sp_std::prelude::*; - -use sp_consensus_beefy_etf::BeefyAuthorityId; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::config] - pub trait Config: frame_system::Config { - /// Authority identifier type - type BeefyId: Member - + Parameter - // todo: use custom signature hashing type instead of hardcoded `Keccak256` - + BeefyAuthorityId - + MaybeSerializeDeserialize - + MaxEncodedLen; - - /// The maximum number of authorities that can be added. - #[pallet::constant] - type MaxAuthorities: Get; - - // TODO - // /// Weights for this pallet. - // type WeightInfo: WeightInfo; - } - - #[pallet::pallet] - pub struct Pallet(_); - - /// publicly verifiable shares for the current round (a resharing) - #[pallet::storage] - pub type Shares = - StorageValue<_, BoundedVec>, T::MaxAuthorities>, ValueQuery>; - - /// public commitments of the the expected validator to etf pubkey - /// assumes order follows the same as the Authorities StorageValue - #[pallet::storage] - pub type Commitments = - StorageValue<_, BoundedVec, ValueQuery>; - - /// the public key for the round (or rounds) - #[pallet::storage] - pub type RoundPublic = StorageValue<_, BoundedVec>, ValueQuery>; - - #[pallet::genesis_config] - pub struct GenesisConfig { - /// (beefy id, commitment, BatchPoK (which technically contains the commitment...)) - pub genesis_resharing: Vec<(T::BeefyId, Vec)>, - /// the round pubkey is the IBE master secret multiplied by a given group generator (e.g r - /// = sP) - pub round_pubkey: Vec, - } - - impl Default for GenesisConfig { - fn default() -> Self { - Self { genesis_resharing: Vec::new(), round_pubkey: Vec::new() } - } - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - Pallet::::initialize(&self.genesis_resharing, self.round_pubkey.clone()) - .expect("The genesis resharing should be correctly derived"); - } - } - - #[pallet::error] - pub enum Error { - TODO, - } - - #[pallet::call] - impl Pallet {} -} - -impl Pallet { - fn initialize( - genesis_resharing: &Vec<(T::BeefyId, Vec)>, - round_key: Vec, - ) -> Result<(), ()> { - let bounded_rk = BoundedVec::>::try_from(round_key) - .expect("The serialized round key should be 144 bytes."); - >::put(bounded_rk); - - let mut unbounded_shares: Vec>> = Vec::new(); - - genesis_resharing.iter().for_each(|(_commitment, pok_bytes)| { - let bounded_pok = BoundedVec::>::try_from(pok_bytes.clone()) - .expect("genesis poks should be well formatted"); - unbounded_shares.push(bounded_pok); - }); - - let bounded_shares = - BoundedVec::>, T::MaxAuthorities>::try_from( - unbounded_shares, - ) - .expect("There should be the correct number of genesis resharings"); - >::put(bounded_shares); - - let bounded_commitments = BoundedVec::::try_from( - genesis_resharing.iter().map(|g| g.0.clone()).collect::>(), - ) - .map_err(|_| ())?; - - Commitments::::put(bounded_commitments); - Ok(()) - } - - pub fn round_pubkey() -> BoundedVec> { - RoundPublic::::get() - } - - pub fn commitments() -> BoundedVec { - Commitments::::get() - } -} - -/// A type to provide commitments, keys, and shares to validators -pub trait RoundCommitmentProvider { - fn get() -> BoundedVec; -} - -impl RoundCommitmentProvider for Pallet { - fn get() -> BoundedVec { - Commitments::::get() - } -} diff --git a/pallets/etf/src/mock.rs b/pallets/etf/src/mock.rs deleted file mode 100644 index bca36bf..0000000 --- a/pallets/etf/src/mock.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::vec; - -use frame_support::{construct_runtime, derive_impl, traits::ConstU32}; -use sp_io::TestExternalities; -use sp_runtime::{app_crypto::bls381::Public, traits::OpaqueKeys, BuildStorage}; -use sp_state_machine::BasicExternalities; - -use crate as pallet_etf; - -pub use sp_consensus_beefy_etf::bls_crypto::AuthorityId as BeefyId; - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Test - { - System: frame_system, - Etf: pallet_etf, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; -} - -impl pallet_etf::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; -} -// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation -// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for aggregatable BLS. A compressed aggregated BLS public key is 144 -// bytes -pub fn mock_beefy_id(id: u8) -> BeefyId { - let mut buf: [u8; 144] = [id; 144]; - // Set to something valid. - buf[0] = 0x02; - let pk = Public::from_raw(buf); - BeefyId::from(pk) -} - -pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { - vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() -} - -pub fn new_test_ext(ids: Vec) -> TestExternalities { - new_test_ext_raw_authorities(mock_authorities(ids)) -} - -pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let genesis_resharing = authorities.iter().map(|(_idx, id)| (id.clone(), vec![2])).collect(); - - pallet_etf::GenesisConfig:: { genesis_resharing, round_pubkey: vec![1] } - .assimilate_storage(&mut t) - .unwrap(); - - t.into() -} diff --git a/pallets/etf/src/tests.rs b/pallets/etf/src/tests.rs deleted file mode 100644 index edd95ef..0000000 --- a/pallets/etf/src/tests.rs +++ /dev/null @@ -1,35 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. -use crate::{self as etf, mock::*, Call, Config, Error, Weight}; -use std::vec; - -#[test] -fn genesis_session_initializes_resharing_and_commitments_with_valid_values() { - let genesis_resharing = vec![(1, vec![2]), (2, vec![2]), (3, vec![2])]; - - let want_resharing = genesis_resharing.clone(); - let genesis_roundkey = [1; 96].to_vec(); - - new_test_ext(vec![1, 2, 3]).execute_with(|| { - // resharings are populated - let resharings = etf::Shares::::get(); - assert_eq!(resharings.len(), 3); - assert_eq!(resharings[0], want_resharing[0].1); - assert_eq!(resharings[1], want_resharing[1].1); - assert_eq!(resharings[2], want_resharing[2].1); - }); -} diff --git a/pallets/randomness-beacon/Cargo.toml b/pallets/randomness-beacon/Cargo.toml deleted file mode 100644 index 1c089cd..0000000 --- a/pallets/randomness-beacon/Cargo.toml +++ /dev/null @@ -1,95 +0,0 @@ -[package] -name = "pallet-randomness-beacon" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -repository.workspace = true -description = "Verifiable Randomness Beacon FRAME pallet" -homepage = "https://substrate.io" - -[lints] -workspace = true - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } -serde = { version = "1.0.197", default-features = false } - -frame-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -frame-system = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -pallet-authorship = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-consensus-beefy-etf = { path = "../../primitives/consensus/beefy-etf", default-features = false, features = ["serde", "bls-experimental"] } -pallet-etf = { path = "../etf", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-session = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false, features = ["serde"] } -sp-std = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } - -w3f-bls = { version = "0.1.3", default-features = false } -ark-serialize = { version = "0.4.0", default-features = false } -ark-std = { version = "0.4.0", default-features = false } -ark-ff = { version = "0.4.0", default-features = false } -ark-bls12-377 = { version = "0.4.0", features = ["curve"], default-features = false } -array-bytes = "6.1" -sha3 = { version = "0.10.0", default-features = false } -sha2 = { version = "0.10.8", default-features = false } -etf-crypto-primitives = { git = "https://github.com/ideal-lab5/etf-sdk.git", default-features = false} - -[dev-dependencies] -frame-election-provider-support = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-balances = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-staking-reward-curve = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-timestamp = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-staking = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -sp-state-machine = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } -pallet-mmr = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing" } - -[features] -default = ["std"] -std = [ - "ark-ff/std", - "ark-std/std", - "ark-serialize/std", - "ark-bls12-377/std", - "codec/std", - "frame-election-provider-support/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-balances/std", - "pallet-session/std", - "pallet-staking/std", - "pallet-timestamp/std", - "scale-info/std", - "serde/std", - "sp-consensus-beefy-etf/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-session/std", - "sp-staking/std", - "sp-state-machine/std", - "sp-std/std", - "pallet-etf/std", - "w3f-bls/std", - "sha3/std", - "sha2/std", - "etf-crypto-primitives/std", - "pallet-authorship/std" -] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-balances/try-runtime", - "pallet-session/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/randomness-beacon/README.md b/pallets/randomness-beacon/README.md deleted file mode 100644 index 35fa330..0000000 --- a/pallets/randomness-beacon/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# pallet-randomness-beacon - -This pallet bridges to a randomness beacon via a relayer. It constructs a **forkless** chain of verifiable randomness following NIST's proposed randomness beacon specification. - -## How it works - -The pallet starts at a genesis block (not necessarily network genesis). -An untrusted relayer component interpolates signatures and pushes them to the beacon. -The beacon verifies the signature and encodes it into storage. -Assume it is using Sha512. -It does this in a way that builds a hash-chain, where each entry looks like: - -https://nvlpubs.nist.gov/nistpubs/ir/2019/NIST.IR.8213-draft.pdf - -```json -{ - "header": { - "block_number": number, - "hash(prev_sig)": string, - "metadata": "todo", - }, - "body": { - "sig": string, - "proof": string - } -} -``` - -Where the metadata field is defined following the randomness beacon standard proposed by NIST. Thus, the metadata contains the following 21 fields: - -When adding a new pulse: -1) get public keys in signature group from each batch PoK -2) \ No newline at end of file diff --git a/pallets/randomness-beacon/src/lib.rs b/pallets/randomness-beacon/src/lib.rs deleted file mode 100644 index 01d35af..0000000 --- a/pallets/randomness-beacon/src/lib.rs +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -#![cfg_attr(not(feature = "std"), no_std)] -use codec::MaxEncodedLen; - -use serde::{Deserialize, Serialize}; - -use frame_support::{ - dispatch::{DispatchResultWithPostInfo, Pays}, - pallet_prelude::*, - traits::{Get, Randomness}, - BoundedVec, -}; - -use frame_system::{offchain::SendTransactionTypes, pallet_prelude::*}; -use sp_std::prelude::*; - -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use etf_crypto_primitives::{tlock::tlock::TLECiphertext, utils::interpolate_threshold_bls}; - -use sp_consensus_beefy_etf::{known_payloads, Commitment, Payload, ValidatorSetId}; -use w3f_bls::{ - DoublePublicKey, DoubleSignature, EngineBLS, Message, SerializableToBytes, TinyBLS377, -}; - -use log::{error, info}; -use sha3::{Digest, Sha3_512}; -use sp_runtime::{ - traits::Hash, - transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, - ValidTransaction, - }, -}; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -pub use pallet::*; - -const LOG_TARGET: &str = "runtime::randomness-beacon"; - -pub type OpaqueSignature = BoundedVec>; - -#[derive( - Default, - Clone, - Eq, - PartialEq, - RuntimeDebugNoBound, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - Serialize, - Deserialize, -)] -pub struct PulseHeader { - pub block_number: BN, - // pub hash_prev: BoundedVec> -} - -#[derive( - Default, - Clone, - Eq, - PartialEq, - RuntimeDebugNoBound, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - Serialize, - Deserialize, -)] -pub struct PulseBody { - pub signature: BoundedVec>, - pub randomness: BoundedVec>, -} - -#[derive( - Default, - Clone, - Eq, - PartialEq, - RuntimeDebugNoBound, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - Serialize, - Deserialize, -)] -pub struct Pulse { - header: PulseHeader, - body: PulseBody, -} - -impl Pulse { - // builds the next pulse from a previous one - pub fn build_next( - signature: OpaqueSignature, - block_number: BN, - // prev: Pulse, - ) -> Self { - let mut hasher = Sha3_512::new(); - hasher.update(signature.to_vec()); - let randomness = hasher.finalize(); - - let bounded_rand = BoundedVec::>::try_from(randomness.to_vec()) - .expect("the hasher should work fix this later though"); - - let header: PulseHeader = PulseHeader { - block_number, - // hash_prev: bounded_hash - }; - - let body = PulseBody { signature, randomness: bounded_rand }; - - Pulse { header, body } - } -} - -#[frame_support::pallet(dev_mode)] -pub mod pallet { - use super::*; - - #[pallet::config] - pub trait Config: - frame_system::Config + SendTransactionTypes> + pallet_etf::Config - { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The maximum number of pulses to store in runtime storage - #[pallet::constant] - type MaxPulses: Get; - - // TODO - // /// Weights for this pallet. - // type WeightInfo: WeightInfo; - } - - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; - - fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - Self::validate_unsigned(source, call) - } - } - - /// the chain of randomness - #[pallet::storage] - pub type Pulses = - StorageMap<_, Blake2_128Concat, BlockNumberFor, Pulse>, OptionQuery>; - - /// the highest block number for which we have encoded a pulse - #[pallet::storage] - pub type Height = StorageValue<_, BlockNumberFor, ValueQuery>; - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::genesis_config] - pub struct GenesisConfig { - pub genesis_pulse: Pulse>, - } - - impl Default for GenesisConfig { - fn default() -> Self { - Self { genesis_pulse: Pulse::default() } - } - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - Pallet::::initialize(&self.genesis_pulse) - .expect("The genesis pulse must be well formatted."); - } - } - - #[pallet::error] - pub enum Error { - /// the origin should be unsigned - InvalidOrigin, - /// the signature could not be verified - InvalidSignature, - SignatureNotDeserializable, - AlreadyInitialized, - /// the bounded runtime storage has reached its limit - PulseOverflow, - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - PulseStored, - InvalidSignatureNotStored, - } - - /// Writes a new block from the randomness beacon into storage if it can be verified - /// - /// * `signatures`: A set of threshold bls signatures (sigma, proof) output from the beacon - /// protocol - /// * `block_number`: The block number on which the pulse was generated (required for - /// verification) - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(0)] - pub fn write_pulse( - origin: OriginFor, - signatures: Vec>, - block_number: BlockNumberFor, - ) -> DispatchResultWithPostInfo { - ensure_none(origin)?; - let round_pk_bytes: Vec = >::round_pubkey().to_vec(); - let rk = - DoublePublicKey::::deserialize_compressed(&round_pk_bytes[..]).unwrap(); - let validator_set_id = 0; //>::validator_set_id(); - let _ = Self::try_add_pulse(signatures, block_number, rk, validator_set_id)?; - - Height::::set(block_number); - Self::deposit_event(Event::PulseStored); - // Waive the fee since the pulse is valid and beneficial - Ok(Pays::No.into()) - } - } -} - -impl Pallet { - /// initialize the genesis state for this pallet - fn initialize(genesis_pulse: &Pulse>) -> Result<(), Error> { - let current_block = >::block_number(); - >::insert(current_block, genesis_pulse); - Ok(()) - } - - /// add a new pulse to the hash chain - fn try_add_pulse( - raw_signatures: Vec>, - block_number: BlockNumberFor, - _rk: DoublePublicKey, - validator_set_id: ValidatorSetId, - ) -> Result<(), Error> { - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let commitment = Commitment { payload, block_number, validator_set_id }; - - // // TODO: error handling - let mut good_sigs = Vec::new(); - raw_signatures.iter().enumerate().for_each(|(idx, rs)| { - let etf_pk = >::commitments()[idx].encode(); - let pk = DoublePublicKey::::deserialize_compressed(&etf_pk[..]).unwrap(); - - if let Ok(sig) = DoubleSignature::::from_bytes(&rs) { - if sig.verify(&Message::new(b"", &commitment.encode()), &pk) { - good_sigs - .push((::Scalar::from((idx as u8) + 1), sig.0)); - } - } - }); - - let sig = interpolate_threshold_bls::(good_sigs); - let mut bytes = Vec::new(); - sig.serialize_compressed(&mut bytes).unwrap(); - let bounded_sig = BoundedVec::>::try_from(bytes) - .map_err(|_| Error::::InvalidSignature)?; - - let pulse = Pulse::build_next( - bounded_sig, - block_number, - // last_pulse - ); - - >::insert(block_number, pulse.clone()); - Ok(()) - } - - pub fn height() -> BlockNumberFor { - Height::::get() - } - - pub fn random_at(at: BlockNumberFor) -> Option>> { - Pulses::::get(at) - } - - /// validate an unsigned transaction sent to this module - pub fn validate_unsigned(source: TransactionSource, call: &Call) -> TransactionValidity { - if let Call::write_pulse { signatures: _, block_number: _ } = call { - // discard pulses not coming from the local node - match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, - _ => { - log::warn!( - target: LOG_TARGET, - "rejecting unsigned beacon pulse because it is not local/in-block." - ); - return InvalidTransaction::Call.into(); - }, - } - - ValidTransaction::with_tag_prefix("RandomnessBeacon") - // We assign the maximum priority for any equivocation report. - .priority(TransactionPriority::MAX) - .longevity(3) - // We don't propagate this. This can never be included on a remote node. - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - - /// submit an unsigned transaction to write a new pulse into storage - pub fn publish_pulse(signatures: Vec>, block_number: BlockNumberFor) -> Option<()> { - use frame_system::offchain::SubmitTransaction; - let call = Call::write_pulse { signatures, block_number }; - let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); - - match res { - Ok(_) => info!("submitted transaction succesfully"), - Err(e) => error!("Failed to submit unsigned transaction: {:?}", e), - } - - Some(()) - } -} - -/// errors for timelock encryption -pub enum TimelockError { - DecryptionFailed, - MissingSecret, - BoundCallFailure, - DecodeFailure, -} - -/// represents a timelock ciphertext -#[derive(Debug, Clone, PartialEq, Decode, Encode, MaxEncodedLen, TypeInfo)] -pub struct Ciphertext { - /// the (AES) ciphertext - pub ciphertext: BoundedVec>, - /// the (AES) nonce - pub nonce: BoundedVec>, - /// the IBE ciphertext(s): for now we assume a single point in the future is used - pub capsule: BoundedVec>, -} - -/// provides timelock encryption using the current slot -pub trait TimelockEncryptionProvider { - /// attempt to decrypt the ciphertext with the current slot secret - fn decrypt_at(ciphertext: &[u8], block_number: BN) -> Result; - - /// get the latest block number for which randomness is known - fn latest() -> BN; -} - -// use ark_serialize::CanonicalDeserialize; -// use w3f_bls::{EngineBLS}; -use etf_crypto_primitives::tlock::tlock::DecryptionResult; - -impl TimelockEncryptionProvider> for Pallet { - fn decrypt_at( - ciphertext_bytes: &[u8], - block_number: BlockNumberFor, - ) -> Result { - if let Some(secret) = Pulses::::get(block_number) { - // let pk = >::round_pubkey(); - // TODO: replace with optimized arkworks types? - let ciphertext: TLECiphertext = - TLECiphertext::deserialize_compressed(ciphertext_bytes) - .map_err(|_| TimelockError::DecodeFailure)?; - - let sig: ::SignatureGroup = - ::SignatureGroup::deserialize_compressed( - &secret.body.signature.to_vec()[..], - ) - .map_err(|_| TimelockError::DecodeFailure)?; - - let plaintext = ciphertext.tld(sig).map_err(|_| TimelockError::DecryptionFailed)?; - - return Ok(plaintext); - } - Err(TimelockError::MissingSecret) - } - - fn latest() -> BlockNumberFor { - return Height::::get(); - } -} - -// use frame_support::StorageHasher; - -impl Randomness> for Pallet { - // this function hashes together the subject with the latest known randomness - fn random(subject: &[u8]) -> (T::Hash, BlockNumberFor) { - let height = Height::::get(); - - let mut entropy = T::Hash::default(); - if let Some(pulse) = Pulses::::get(height) { - entropy = - (subject, height, pulse.body.randomness.clone()).using_encoded(T::Hashing::hash); - } - - (entropy, height) - } -} diff --git a/pallets/randomness-beacon/src/mock.rs b/pallets/randomness-beacon/src/mock.rs deleted file mode 100644 index ade399b..0000000 --- a/pallets/randomness-beacon/src/mock.rs +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -use std::vec; - -use codec::Encode; -use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_consensus_beefy_etf::{mmr::MmrLeafVersion, test_utils::etf_genesis}; -use sp_core::Pair; -use sp_io::TestExternalities; -use sp_runtime::{ - app_crypto::bls377::Public, - impl_opaque_keys, - traits::{ConvertInto, Keccak256, OpaqueKeys}, - BuildStorage, -}; -use sp_state_machine::BasicExternalities; - -use crate as pallet_randomness_beacon; - -pub use sp_consensus_beefy_etf::{bls_crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider}; - -impl_opaque_keys! { - pub struct MockSessionKeys { - pub dummy: pallet_beefy::Pallet, - } -} - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Test - { - System: frame_system, - Session: pallet_session, - Mmr: pallet_mmr, - Beacon: pallet_randomness_beacon, - Etf: pallet_etf, - Beefy: pallet_beefy, - BeefyMmr: pallet_beefy_mmr, - } -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Test { - type Block = Block; -} - -impl pallet_session::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = u64; - type ValidatorIdOf = ConvertInto; - type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; - type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; - type SessionManager = MockSessionManager; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = MockSessionKeys; - type WeightInfo = (); -} - -// pub type MmrLeaf = sp_consensus_beefy_etf::mmr::MmrLeaf< -// frame_system::pallet_prelude::BlockNumberFor, -// ::Hash, -// pallet_beefy_mmr::MerkleRootOf, -// Vec, -// >; - -impl pallet_mmr::Config for Test { - const INDEXING_PREFIX: &'static [u8] = b"mmr"; - type Hashing = Keccak256; - type LeafData = BeefyMmr; - type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); - type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; -} - -impl pallet_etf::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; -} - -impl pallet_beefy::Config for Test { - type BeefyId = BeefyId; - type MaxAuthorities = ConstU32<100>; - type MaxNominators = ConstU32<1000>; - type MaxSetIdSessionEntries = ConstU64<100>; - type OnNewValidatorSet = BeefyMmr; - type WeightInfo = (); - type KeyOwnerProof = sp_core::Void; - type EquivocationReportSystem = (); - type RoundCommitmentProvider = Etf; -} - -parameter_types! { - pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(1, 5); -} - -impl pallet_beefy_mmr::Config for Test { - type LeafVersion = LeafVersion; - - type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyBlsToEthereum; - - type LeafExtra = Vec; - - type BeefyDataProvider = DummyDataProvider; -} - -pub struct DummyDataProvider; -impl BeefyDataProvider> for DummyDataProvider { - fn extra_data() -> Vec { - let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; - col.sort(); - binary_merkle_tree::merkle_root::<::Hashing, _>( - col.into_iter().map(|pair| pair.encode()), - ) - .as_ref() - .to_vec() - } -} - -impl pallet_randomness_beacon::Config for Test { - type RuntimeEvent = RuntimeEvent; - type MaxPulses = ConstU32<256000>; -} - -pub struct MockSessionManager; -impl pallet_session::SessionManager for MockSessionManager { - fn end_session(_: sp_staking::SessionIndex) {} - fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { - if idx == 0 || idx == 1 { - Some(vec![1, 2]) - } else if idx == 2 { - Some(vec![3, 4]) - } else { - None - } - } -} - -// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation -// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for -// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, -// with the first one containing information to reconstruct the uncompressed key. -pub fn mock_beefy_id(id: u8) -> BeefyId { - // generate a new keypair and get the public key - let kp = sp_core::bls::Pair::from_seed_slice(&[id; 32]).unwrap(); - BeefyId::from(kp.public()) -} - -pub fn mock_authorities(vec: Vec) -> Vec<(u64, BeefyId)> { - vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect() -} - -pub fn new_test_ext(ids: Vec) -> TestExternalities { - new_test_ext_raw_authorities(mock_authorities(ids)) -} - -pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let session_keys: Vec<_> = authorities - .iter() - .enumerate() - .map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) - .collect(); - - BasicExternalities::execute_with_storage(&mut t, || { - for (ref id, ..) in &session_keys { - frame_system::Pallet::::inc_providers(id); - } - }); - - let (round_pubkey, genesis_resharing) = etf_genesis::( - authorities.iter().map(|(_, id)| id.clone()).collect::>(), - ); - - pallet_etf::GenesisConfig:: { - genesis_resharing, - round_pubkey, - _phantom: Default::default(), - } - .assimilate_storage(&mut t) - .unwrap(); - - pallet_session::GenesisConfig:: { keys: session_keys } - .assimilate_storage(&mut t) - .unwrap(); - - t.into() -} diff --git a/pallets/randomness-beacon/src/tests.rs b/pallets/randomness-beacon/src/tests.rs deleted file mode 100644 index 8b2a776..0000000 --- a/pallets/randomness-beacon/src/tests.rs +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2024 by Ideal Labs, LLC - * - * 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. - */ - -use crate::{self as beacon, mock::*, BlockNumberFor, Call, Config, Error, Weight}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use codec::Encode; -use frame_support::{assert_ok, traits::OnInitialize}; -use sha2::Sha256; -use sp_consensus_beefy_etf::{known_payloads, Commitment, Payload, ValidatorSetId}; -use sp_core::{bls377, ByteArray, Pair}; -use std::vec; - -use ark_ff::Zero; -use etf_crypto_primitives::{ - proofs::hashed_el_gamal_sigma::BatchPoK, utils::interpolate_threshold_bls, -}; -use w3f_bls::{ - single_pop_aggregator::SignatureAggregatorAssumingPoP, DoublePublicKey, DoublePublicKeyScheme, - DoubleSignature, EngineBLS, Keypair, Message, PublicKey, PublicKeyInSignatureGroup, - SerializableToBytes, Signature, Signed, TinyBLS, TinyBLS377, -}; - -fn init_block(block: u64) { - System::set_block_number(block); - Session::on_initialize(block); -} - -fn calculate_signature( - id: u8, - serialized_resharing: &[u8], - message: &[u8], -) -> (bls377::Public, bls377::Signature) { - let kp = sp_core::bls::Pair::from_seed_slice(&[id; 32]).unwrap(); - let etf_kp = kp.acss_recover(serialized_resharing, 1).unwrap(); - (etf_kp.public(), etf_kp.sign(message)) -} - -#[test] -fn test_genesis() { - // for simplicity of simulating a beacon, we use a single validator model - new_test_ext(vec![1]).execute_with(|| { - let pulses = beacon::Pulses::::get(); - assert!(pulses.is_empty()); - }); -} - -#[test] -fn test_can_write_single_pulse() { - new_test_ext(vec![1, 2, 3]).execute_with(|| { - let pulses = beacon::Pulses::::get(); - assert_eq!(pulses.len(), 0); - - let round_pk_bytes: Vec = >::round_pubkey().to_vec(); - let rk = - DoublePublicKey::::deserialize_compressed(&round_pk_bytes[..]).unwrap(); - // now we write a new pulse... - let resharing_bytes_1 = &pallet_etf::Shares::::get()[0]; - let resharing_bytes_2 = &pallet_etf::Shares::::get()[1]; - let resharing_bytes_3 = &pallet_etf::Shares::::get()[2]; - - // // convert to batchpok - let etf_pk_1 = &pallet_etf::Commitments::::get()[0]; - let etf_pk_2 = &pallet_etf::Commitments::::get()[1]; - let etf_pk_3 = &pallet_etf::Commitments::::get()[2]; - - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let validator_set_id = >::validator_set_id(); - let block_number: BlockNumberFor = 1; - let commitment = Commitment { payload, block_number, validator_set_id }; - - // let mut pub_keys_in_sig_grp: Vec> = Vec::new(); - - let (_pk1, signature_1) = calculate_signature(1, resharing_bytes_1, &commitment.encode()); - - let pk1_ref: &[u8] = etf_pk_1.as_ref(); - let pk1_bytes_pub = &pk1_ref[48..144]; - let pk1_bytes_sig = &pk1_ref[0..48]; - - let pk1_pub = - ::PublicKeyGroup::deserialize_compressed(pk1_bytes_pub) - .unwrap(); - let pk1_sig = - ::SignatureGroup::deserialize_compressed(pk1_bytes_sig) - .unwrap(); - - let sig_bytes_1: &[u8] = signature_1.as_ref(); - let sig_1 = DoubleSignature::::from_bytes(sig_bytes_1).unwrap(); - - let (_pk2, signature_2) = calculate_signature(2, resharing_bytes_2, &commitment.encode()); - let sig_bytes_2: &[u8] = signature_2.as_ref(); - - let sig_2 = DoubleSignature::::from_bytes(sig_bytes_2).unwrap(); - - let mut pk2_bytes: &[u8] = etf_pk_2.as_ref(); - let pk2_bytes_pub = &pk2_bytes[48..144]; - let pk2_bytes_sig = &pk2_bytes[0..48]; - let pk2_pub = - ::PublicKeyGroup::deserialize_compressed(pk2_bytes_pub) - .unwrap(); - let pk2_sig = - ::SignatureGroup::deserialize_compressed(pk2_bytes_sig) - .unwrap(); - - let (_pk3, signature_3) = calculate_signature(3, resharing_bytes_3, &commitment.encode()); - let sig_bytes_3: &[u8] = signature_3.as_ref(); - let sig_3 = DoubleSignature::::from_bytes(sig_bytes_3).unwrap(); - - let mut pk3_bytes: &[u8] = etf_pk_3.as_ref(); - let pk3_bytes_pub = &pk3_bytes[48..144]; - let pk3_bytes_sig = &pk3_bytes[0..48]; - let pk3_pub = - ::PublicKeyGroup::deserialize_compressed(pk3_bytes_pub) - .unwrap(); - let pk3_sig = - ::SignatureGroup::deserialize_compressed(pk3_bytes_sig) - .unwrap(); - - let message = Message::new(b"", &commitment.encode()); - let mut prover_aggregator = - SignatureAggregatorAssumingPoP::::new(message.clone()); - - let mut serialized_sig = Vec::new(); - let sig = &(&prover_aggregator).signature(); - sig.serialize_compressed(&mut serialized_sig).unwrap(); - - assert_ok!(Beacon::write_pulse( - RuntimeOrigin::none(), - // serialized_sig.to_vec(), - vec![sig_bytes_1.to_vec(), sig_bytes_2.to_vec(), sig_bytes_3.to_vec()], - 1, - )); - // step to next block - init_block(1); - - let pulses = beacon::Pulses::::get(); - assert_eq!(pulses.len(), 1); - }); -} - -#[test] -fn test_can_write_many_pulses() { - new_test_ext(vec![1]).execute_with(|| { - let pulses = beacon::Pulses::::get(); - assert_eq!(pulses.len(), 0); - - let round_pk_bytes: Vec = >::round_pubkey().to_vec(); - let rk = - DoublePublicKey::::deserialize_compressed(&round_pk_bytes[..]).unwrap(); - // now we write a new pulse... - let resharing_bytes_1 = &pallet_etf::Shares::::get()[0]; - - // // convert to batchpok - let etf_pk_1 = &pallet_etf::Commitments::::get()[0]; - - let payload = Payload::from_single_entry(known_payloads::ETF_SIGNATURE, Vec::new()); - let validator_set_id = >::validator_set_id(); - let block_number: BlockNumberFor = 1; - let commitment = Commitment { payload, block_number, validator_set_id }; - - let (_pk1, signature_1) = calculate_signature(1, resharing_bytes_1, &commitment.encode()); - let sig_bytes_1: &[u8] = signature_1.as_ref(); - assert_ok!(Beacon::write_pulse(RuntimeOrigin::none(), vec![sig_bytes_1.to_vec()], 1,)); - // step to next block - init_block(1); - - let pulses = beacon::Pulses::::get(); - assert_eq!(pulses.len(), 1); - - let (_pk1, signature_1_next) = - calculate_signature(1, resharing_bytes_1, &commitment.encode()); - let sig_bytes_1_next: &[u8] = signature_1_next.as_ref(); - assert_ok!(Beacon::write_pulse(RuntimeOrigin::none(), vec![sig_bytes_1_next.to_vec()], 2,)); - // step to next block - init_block(2); - - let pulses = beacon::Pulses::::get(); - assert_eq!(pulses.len(), 2); - }); -} diff --git a/primitives/consensus/beefy-etf/Cargo.toml b/primitives/consensus/beefy-etf/Cargo.toml deleted file mode 100644 index 25c0309..0000000 --- a/primitives/consensus/beefy-etf/Cargo.toml +++ /dev/null @@ -1,77 +0,0 @@ -[package] -name = "sp-consensus-beefy-etf" -version = "13.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "Primitives for BEEFY protocol." - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -serde = { optional = true, features = ["alloc", "derive"], workspace = true } -sp-api = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-application-crypto = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-core = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-crypto-hashing = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-io = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-mmr-primitives = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-runtime = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -sp-keystore = { git = "https://github.com/ideal-lab5/polkadot-sdk.git", branch = "testing", default-features = false } -strum = { version = "0.24.1", features = ["derive"], default-features = false } -lazy_static = { version = "1.4.0", optional = true } -ark-std = { version = "0.4.0", default-features = false } -ark-serialize = { version = "0.4.0", default-features = false } -rand = {version = "0.8", default-features = false } -w3f-bls = {version = "0.1.3", default-features = false } -etf-crypto-primitives = { git = "https://github.com/ideal-lab5/etf-sdk.git", default-features = false} - -[dev-dependencies] -array-bytes = "6.1" - -[features] -default = ["std"] -std = [ - "codec/std", - "dep:lazy_static", - "scale-info/std", - "serde/std", - "sp-api/std", - "sp-application-crypto/std", - "sp-core/std", - "sp-crypto-hashing/std", - "sp-io/std", - "sp-keystore/std", - "sp-mmr-primitives/std", - "sp-runtime/std", - "strum/std", - "ark-std/std", - "ark-serialize/std", - "rand/std", - "w3f-bls/std", - "etf-crypto-primitives/std" -] - -# Serde support without relying on std features. -serde = [ - "dep:serde", - "scale-info/serde", - "sp-application-crypto/serde", - "sp-core/serde", - "sp-runtime/serde", -] - -# This feature adds BLS crypto primitives. It should not be used in production since -# the BLS implementation and interface may still be subject to significant change. -bls-experimental = [ - "sp-application-crypto/bls-experimental", - "sp-core/bls-experimental", -] diff --git a/primitives/consensus/beefy-etf/src/commitment.rs b/primitives/consensus/beefy-etf/src/commitment.rs deleted file mode 100644 index 4fd9e1b..0000000 --- a/primitives/consensus/beefy-etf/src/commitment.rs +++ /dev/null @@ -1,526 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode, Error, Input}; -use core::cmp; -use scale_info::TypeInfo; - -use crate::{Payload, ValidatorSetId}; - -/// A commitment signed by GRANDPA validators as part of BEEFY protocol. -/// -/// The commitment contains a [payload](Commitment::payload) extracted from the finalized block at -/// height [block_number](Commitment::block_number). -/// GRANDPA validators collect signatures on commitments and a stream of such signed commitments -/// (see [SignedCommitment]) forms the BEEFY protocol. -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)] -pub struct Commitment { - /// A collection of payloads to be signed, see [`Payload`] for details. - /// - /// One of the payloads should be some form of cumulative representation of the chain (think - /// MMR root hash). Additionally one of the payloads should also contain some details that - /// allow the light client to verify next validator set. The protocol does not enforce any - /// particular format of this data, nor how often it should be present in commitments, however - /// the light client has to be provided with full validator set whenever it performs the - /// transition (i.e. importing first block with - /// [validator_set_id](Commitment::validator_set_id) incremented). - pub payload: Payload, - - /// Finalized block number this commitment is for. - /// - /// GRANDPA validators agree on a block they create a commitment for and start collecting - /// signatures. This process is called a round. - /// There might be multiple rounds in progress (depending on the block choice rule), however - /// since the payload is supposed to be cumulative, it is not required to import all - /// commitments. - /// BEEFY light client is expected to import at least one commitment per epoch, - /// but is free to import as many as it requires. - pub block_number: TBlockNumber, - - /// BEEFY validator set supposed to sign this commitment. - /// - /// Validator set is changing once per epoch. The Light Client must be provided by details - /// about the validator set whenever it's importing first commitment with a new - /// `validator_set_id`. Validator set data MUST be verifiable, for instance using - /// [payload](Commitment::payload) information. - pub validator_set_id: ValidatorSetId, -} - -impl cmp::PartialOrd for Commitment -where - TBlockNumber: cmp::Ord, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl cmp::Ord for Commitment -where - TBlockNumber: cmp::Ord, -{ - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.validator_set_id - .cmp(&other.validator_set_id) - .then_with(|| self.block_number.cmp(&other.block_number)) - .then_with(|| self.payload.cmp(&other.payload)) - } -} - -/// A commitment with matching GRANDPA validators' signatures. -/// -/// Note that SCALE-encoding of the structure is optimized for size efficiency over the wire, -/// please take a look at custom [`Encode`] and [`Decode`] implementations and -/// `CompactSignedCommitment` struct. -#[derive(Clone, Debug, PartialEq, Eq, TypeInfo)] -pub struct SignedCommitment { - /// The commitment signatures are collected for. - pub commitment: Commitment, - /// GRANDPA validators' signatures for the commitment. - /// - /// The length of this `Vec` must match number of validators in the current set (see - /// [Commitment::validator_set_id]). - pub signatures: Vec>, -} - -impl core::fmt::Display - for SignedCommitment -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let signatures_count = self.signatures.iter().filter(|s| s.is_some()).count(); - write!( - f, - "SignedCommitment(commitment: {:?}, signatures_count: {})", - self.commitment, signatures_count - ) - } -} - -impl SignedCommitment { - /// Return the number of collected signatures. - pub fn no_of_signatures(&self) -> usize { - self.signatures.iter().filter(|x| x.is_some()).count() - } -} - -/// Type to be used to denote placement of signatures -type BitField = Vec; -/// Compress 8 bit values into a single u8 Byte -const CONTAINER_BIT_SIZE: usize = 8; - -/// Compressed representation of [`SignedCommitment`], used for encoding efficiency. -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -struct CompactSignedCommitment { - /// The commitment, unchanged compared to regular [`SignedCommitment`]. - commitment: Commitment, - /// A bitfield representing presence of a signature coming from a validator at some index. - /// - /// The bit at index `0` is set to `1` in case we have a signature coming from a validator at - /// index `0` in in the original validator set. In case the [`SignedCommitment`] does not - /// contain that signature the `bit` will be set to `0`. Bits are packed into `Vec` - signatures_from: BitField, - /// Number of validators in the Validator Set and hence number of significant bits in the - /// [`signatures_from`] collection. - /// - /// Note this might be smaller than the size of `signatures_compact` in case some signatures - /// are missing. - validator_set_len: u32, - /// A `Vec` containing all `Signature`s present in the original [`SignedCommitment`]. - /// - /// Note that in order to associate a `Signature` from this `Vec` with a validator, one needs - /// to look at the `signatures_from` bitfield, since some validators might have not produced a - /// signature. - signatures_compact: Vec, -} - -impl<'a, TBlockNumber: Clone, TSignature> CompactSignedCommitment { - /// Packs a `SignedCommitment` into the compressed `CompactSignedCommitment` format for - /// efficient network transport. - fn pack(signed_commitment: &'a SignedCommitment) -> Self { - let SignedCommitment { commitment, signatures } = signed_commitment; - let validator_set_len = signatures.len() as u32; - - let signatures_compact: Vec<&'a TSignature> = - signatures.iter().filter_map(|x| x.as_ref()).collect(); - let bits = { - let mut bits: Vec = - signatures.iter().map(|x| if x.is_some() { 1 } else { 0 }).collect(); - // Resize with excess bits for placement purposes - let excess_bits_len = - CONTAINER_BIT_SIZE - (validator_set_len as usize % CONTAINER_BIT_SIZE); - bits.resize(bits.len() + excess_bits_len, 0); - bits - }; - - let mut signatures_from: BitField = vec![]; - let chunks = bits.chunks(CONTAINER_BIT_SIZE); - for chunk in chunks { - let mut iter = chunk.iter().copied(); - let mut v = iter.next().unwrap() as u8; - - for bit in iter { - v <<= 1; - v |= bit as u8; - } - - signatures_from.push(v); - } - - Self { - commitment: commitment.clone(), - signatures_from, - validator_set_len, - signatures_compact, - } - } - - /// Unpacks a `CompactSignedCommitment` into the uncompressed `SignedCommitment` form. - fn unpack( - temporary_signatures: CompactSignedCommitment, - ) -> SignedCommitment { - let CompactSignedCommitment { - commitment, - signatures_from, - validator_set_len, - signatures_compact, - } = temporary_signatures; - let mut bits: Vec = vec![]; - - for block in signatures_from { - for bit in 0..CONTAINER_BIT_SIZE { - bits.push((block >> (CONTAINER_BIT_SIZE - bit - 1)) & 1); - } - } - - bits.truncate(validator_set_len as usize); - - let mut next_signature = signatures_compact.into_iter(); - let signatures: Vec> = bits - .iter() - .map(|&x| if x == 1 { next_signature.next() } else { None }) - .collect(); - - SignedCommitment { commitment, signatures } - } -} - -impl Encode for SignedCommitment -where - TBlockNumber: Encode + Clone, - TSignature: Encode, -{ - fn using_encoded R>(&self, f: F) -> R { - let temp = CompactSignedCommitment::pack(self); - temp.using_encoded(f) - } -} - -impl Decode for SignedCommitment -where - TBlockNumber: Decode + Clone, - TSignature: Decode, -{ - fn decode(input: &mut I) -> Result { - let temp = CompactSignedCommitment::decode(input)?; - Ok(CompactSignedCommitment::unpack(temp)) - } -} - -/// A [SignedCommitment] with a version number. -/// -/// This variant will be appended to the block justifications for the block -/// for which the signed commitment has been generated. -/// -/// Note that this enum is subject to change in the future with introduction -/// of additional cryptographic primitives to BEEFY. -#[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] -pub enum VersionedFinalityProof { - #[codec(index = 1)] - /// Current active version - V1(SignedCommitment), -} - -impl core::fmt::Display for VersionedFinalityProof { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - VersionedFinalityProof::V1(sc) => write!(f, "VersionedFinalityProof::V1({})", sc), - } - } -} - -impl From> for VersionedFinalityProof { - fn from(commitment: SignedCommitment) -> Self { - VersionedFinalityProof::V1(commitment) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads}; - use codec::Decode; - use sp_core::Pair; - use sp_crypto_hashing::keccak_256; - - #[cfg(feature = "bls-experimental")] - use crate::bls_crypto::Signature as BlsSignature; - - type TestCommitment = Commitment; - - const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment"); - - // Types for bls-less commitment - type TestEcdsaSignedCommitment = SignedCommitment; - type TestVersionedFinalityProof = VersionedFinalityProof; - - // Types for commitment supporting aggregatable bls signature - #[cfg(feature = "bls-experimental")] - #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] - struct BlsAggregatableSignature(BlsSignature); - - #[cfg(feature = "bls-experimental")] - #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] - struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature); - - #[cfg(feature = "bls-experimental")] - type TestBlsSignedCommitment = SignedCommitment; - - // Generates mock aggregatable ecdsa signature for generating test commitment - // BLS signatures - fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) { - let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); - - let msg = keccak_256(b"This is the first message"); - let sig1 = alice.sign_prehashed(&msg); - - let msg = keccak_256(b"This is the second message"); - let sig2 = alice.sign_prehashed(&msg); - - (sig1.into(), sig2.into()) - } - - // Generates mock aggregatable bls signature for generating test commitment - // BLS signatures - #[cfg(feature = "bls-experimental")] - fn mock_bls_signatures() -> (BlsSignature, BlsSignature) { - let alice = sp_core::bls::Pair::from_string("//Alice", None).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 - let payload = - 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); - - // then - assert_eq!(decoded, Ok(commitment)); - assert_eq!( - encoded, - array_bytes::hex2bytes_unchecked( - "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" - ) - ); - } - - #[test] - fn signed_commitment_encode_decode_ecdsa() { - // given - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - let commitment: TestCommitment = - Commitment { payload, block_number: 5, validator_set_id: 0 }; - - let ecdsa_sigs = mock_ecdsa_signatures(); - - 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(&ecdsa_signed); - let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded); - - // then - assert_eq!(decoded, Ok(ecdsa_signed)); - assert_eq!( - encoded, - array_bytes::hex2bytes_unchecked( - "\ - 046d68343048656c6c6f20576f726c64210500000000000000000000000000000000000000000000000\ - 4300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746c\ - c321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9aa\ - acdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6\ - a0046395a71681be3d0c2a00\ - " - ) - ); - } - - #[test] - #[cfg(feature = "bls-experimental")] - fn signed_commitment_encode_decode_ecdsa_n_bls() { - // given - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - let commitment: TestCommitment = - Commitment { payload, block_number: 5, validator_set_id: 0 }; - - let ecdsa_sigs = mock_ecdsa_signatures(); - - //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); - - // then - assert_eq!(decoded, Ok(ecdsa_and_bls_signed)); - assert_eq!( - encoded, - array_bytes::hex2bytes_unchecked( - "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba015dd1c9b2237e54baa93d232cdf83a430b58a5efbc2f86ca1bab173a315ff6f15bef161425750c028055e9a23947b73002889a8b22168628438875a8ef25d76db998a80187b50719471286f054f3b3809b77a0cd87d7fe9c1a9d5d562683e25a70610f0804e92340549a43a7159b77b0c2d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a001074884b6998c82331bd57ffa0a02cbfd02483c765b9216eab6a1fc119206236bf7971be68acaebff7400edee943240006a6096c9cfa65e9eb4e67f025c27112d14b4574fb208c439500f45cf3a8060f6cf009044f3141cce0364a7c2710a19b1bdf4abf27f86e5e3db08bddd35a7d12" - ) - ); - } - - #[test] - fn signed_commitment_count_signatures() { - // given - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - let commitment: TestCommitment = - Commitment { payload, block_number: 5, validator_set_id: 0 }; - - let sigs = mock_ecdsa_signatures(); - - let mut signed = SignedCommitment { - commitment, - signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], - }; - assert_eq!(signed.no_of_signatures(), 2); - - // when - signed.signatures[2] = None; - - // then - assert_eq!(signed.no_of_signatures(), 1); - } - - #[test] - fn commitment_ordering() { - fn commitment( - block_number: u128, - validator_set_id: crate::ValidatorSetId, - ) -> TestCommitment { - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - Commitment { payload, block_number, validator_set_id } - } - - // given - let a = commitment(1, 0); - let b = commitment(2, 1); - let c = commitment(10, 0); - let d = commitment(10, 1); - - // then - assert!(a < b); - assert!(a < c); - assert!(c < b); - assert!(c < d); - assert!(b < d); - } - - #[test] - fn versioned_commitment_encode_decode() { - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - let commitment: TestCommitment = - Commitment { payload, block_number: 5, validator_set_id: 0 }; - - let sigs = mock_ecdsa_signatures(); - - let signed = SignedCommitment { - commitment, - signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], - }; - - let versioned = TestVersionedFinalityProof::V1(signed.clone()); - - let encoded = codec::Encode::encode(&versioned); - - assert_eq!(1, encoded[0]); - assert_eq!(encoded[1..], codec::Encode::encode(&signed)); - - let decoded = TestVersionedFinalityProof::decode(&mut &*encoded); - - assert_eq!(decoded, Ok(versioned)); - } - - #[test] - fn large_signed_commitment_encode_decode() { - // given - let payload = - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); - let commitment: TestCommitment = - Commitment { payload, block_number: 5, validator_set_id: 0 }; - - let sigs = mock_ecdsa_signatures(); - - let signatures: Vec> = (0..1024) - .into_iter() - .map(|x| if x < 340 { None } else { Some(sigs.0.clone()) }) - .collect(); - let signed = SignedCommitment { commitment, signatures }; - - // when - let encoded = codec::Encode::encode(&signed); - let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded); - - // then - assert_eq!(decoded, Ok(signed)); - assert_eq!(encoded, LARGE_RAW_COMMITMENT); - } -} diff --git a/primitives/consensus/beefy-etf/src/lib.rs b/primitives/consensus/beefy-etf/src/lib.rs deleted file mode 100644 index 2f3b511..0000000 --- a/primitives/consensus/beefy-etf/src/lib.rs +++ /dev/null @@ -1,600 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![cfg_attr(not(feature = "std"), no_std)] - -//! Primitives for BEEFY protocol. -//! -//! The crate contains shared data types used by BEEFY protocol and documentation (in a form of -//! code) for building a BEEFY light client. -//! -//! BEEFY is a gadget that runs alongside another finality gadget (for instance GRANDPA). -//! For simplicity (and the initially intended use case) the documentation says GRANDPA in places -//! where a more abstract "Finality Gadget" term could be used, but there is no reason why BEEFY -//! wouldn't run with some other finality scheme. -//! BEEFY validator set is supposed to be tracking the Finality Gadget validator set, but note that -//! it will use a different set of keys. For Polkadot use case we plan to use `secp256k1` for BEEFY, -//! while GRANDPA uses `ed25519`. - -extern crate alloc; - -mod commitment; -mod payload; - -pub mod mmr; -pub mod witness; - -/// Test utilities -#[cfg(feature = "std")] -pub mod test_utils; - -pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; -pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; - -use alloc::vec::Vec; -use codec::{Codec, Decode, Encode}; -use core::fmt::{Debug, Display}; -use scale_info::TypeInfo; -use sp_application_crypto::{AppCrypto, AppPublic, ByteArray, RuntimeAppPublic}; -use sp_core::H256; -use sp_runtime::traits::{Hash, Keccak256, NumberFor}; - -/// Key type for BEEFY module. -pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BEEFY; - -/// Trait representing BEEFY authority id, including custom signature verification. -/// -/// Accepts custom hashing fn for the message and custom convertor fn for the signer. -pub trait BeefyAuthorityId: RuntimeAppPublic { - /// Verify a signature. - /// - /// Return `true` if signature over `msg` is valid for this id. - fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; -} - -/// Hasher used for BEEFY signatures. -pub type BeefySignatureHasher = sp_runtime::traits::Keccak256; - -/// A trait bound which lists all traits which are required to be implemented by -/// a BEEFY AuthorityId type in order to be able to be used in BEEFY Keystore -pub trait AuthorityIdBound: - Codec - + Debug - + Clone - + AsRef<[u8]> - + ByteArray - + AppPublic - + AppCrypto - + RuntimeAppPublic - + Display - + BeefyAuthorityId -{ -} - -/// BEEFY cryptographic types for ECDSA crypto -/// -/// This module basically introduces four crypto types: -/// - `ecdsa_crypto::Pair` -/// - `ecdsa_crypto::Public` -/// - `ecdsa_crypto::Signature` -/// - `ecdsa_crypto::AuthorityId` -/// -/// Your code should use the above types as concrete types for all crypto related -/// functionality. -pub mod ecdsa_crypto { - use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; - use sp_application_crypto::{app_crypto, ecdsa}; - use sp_core::crypto::Wraps; - - app_crypto!(ecdsa, KEY_TYPE); - - /// Identity of a BEEFY authority using ECDSA as its crypto. - pub type AuthorityId = Public; - - /// Signature for a BEEFY authority using ECDSA as its crypto. - pub type AuthoritySignature = Signature; - - impl BeefyAuthorityId for AuthorityId - where - ::Output: Into<[u8; 32]>, - { - fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - let msg_hash = ::hash(msg).into(); - match sp_io::crypto::secp256k1_ecdsa_recover_compressed( - signature.as_inner_ref().as_ref(), - &msg_hash, - ) { - Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(self), - _ => false, - } - } - } - impl AuthorityIdBound for AuthorityId {} -} - -/// BEEFY cryptographic types for BLS crypto -/// -/// This module basically introduces four crypto types: -/// - `bls_crypto::Pair` -/// - `bls_crypto::Public` -/// - `bls_crypto::Signature` -/// - `bls_crypto::AuthorityId` -/// -/// Your code should use the above types as concrete types for all crypto related -/// functionality. - -// #[cfg(feature = "bls-experimental")] -pub mod bls_crypto { - use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; - use sp_application_crypto::{app_crypto, bls377}; - use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; - - app_crypto!(bls377, 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; - - impl BeefyAuthorityId for AuthorityId - where - ::Output: Into<[u8; 32]>, - { - fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { - // `w3f-bls` library uses IETF hashing standard and as such does not expose - // a choice of hash-to-field function. - // We are directly calling into the library to avoid introducing new host call. - // and because BeefyAuthorityId::verify is being called in the runtime so we don't have - - BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) - } - } - impl AuthorityIdBound for AuthorityId {} -} - -/// BEEFY cryptographic types for (ECDSA,BLS) crypto pair -/// -/// This module basically introduces four crypto types: -/// - `ecdsa_bls_crypto::Pair` -/// - `ecdsa_bls_crypto::Public` -/// - `ecdsa_bls_crypto::Signature` -/// - `ecdsa_bls_crypto::AuthorityId` -/// -/// Your code should use the above types as concrete types for all crypto related -/// functionality. -#[cfg(all(feature = "bls-experimental"))] -pub mod ecdsa_bls_crypto { - use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; - use sp_application_crypto::{app_crypto, ecdsa_bls377}; - // use sp_core::{crypto::Wraps, ecdsa_bls381::Pair as EcdsaBlsPair}; - - app_crypto!(ecdsa_bls377, KEY_TYPE); - - /// Identity of a BEEFY authority using (ECDSA,BLS) as its crypto. - pub type AuthorityId = Public; - - /// Signature for a BEEFY authority using (ECDSA,BLS) as its crypto. - pub type AuthoritySignature = Signature; - - impl BeefyAuthorityId for AuthorityId - where - H: Hash, - H::Output: Into<[u8; 32]>, - { - fn verify(&self, _signature: &::Signature, _msg: &[u8]) -> bool { - // We can not simply call - // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` - // because that invokes ECDSA default verification which performs Blake2b hash - // which we don't want. This is because ECDSA signatures are meant to be verified - // on Ethereum network where Keccak hasher is significantly cheaper than Blake2b. - // See Figure 3 of [OnSc21](https://www.scitepress.org/Papers/2021/106066/106066.pdf) - // for comparison. - - // TODO: I'm not actually using this currently, just doing this so it will compile.. - false - // this is the original code but I can't get it to compile for some reason... - // something about a missing panic handler appears when I try to enable the full_crypto - // feature for sp-core and sp-application-crypto - // not sure what I broke exactly to cause this, but we - // EcdsaBlsPair::verify_with_hasher::( - // signature.as_inner_ref(), - // msg, - // self.as_inner_ref(), - // ) - } - } - - impl AuthorityIdBound for AuthorityId {} -} - -/// The `ConsensusEngineId` of BEEFY. -pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; - -/// Authority set id starts with zero at BEEFY pallet genesis. -pub const GENESIS_AUTHORITY_SET_ID: u64 = 0; - -/// A typedef for validator set id. -pub type ValidatorSetId = u64; - -// /// A set of BEEFY authorities, a.k.a. validators. -// #[cfg(not(feature = "bls-experimental"))] -// #[derive(Decode, Encode, Debug, PartialEq, Clone, TypeInfo)] -// pub struct ValidatorSet { -// /// Public keys of the validator set elements -// validators: Vec, -// /// Identifier of the validator set -// id: ValidatorSetId, -// } - -/// A set of BEEFY authorities, a.k.a. validators. -// #[cfg(feature = "bls-experimental")] -#[derive(Decode, Encode, Debug, PartialEq, Clone, TypeInfo)] -pub struct ValidatorSet { - /// Public keys of the validator set elements - validators: Vec, - /// Public round key commitments for the validators - commitments: Vec, - /// Identifier of the validator set - id: ValidatorSetId, -} - -// #[cfg(feature = "bls-experimental")] -impl ValidatorSet { - /// Return a validator set with the given validators and set id. - pub fn new(validators: I, commitments: I, id: ValidatorSetId) -> Option - where - I: IntoIterator, - { - let validators: Vec = validators.into_iter().collect(); - let commitments: Vec = commitments.into_iter().collect(); - if validators.is_empty() || commitments.is_empty() { - // No validators; the set would be empty. - // Or the validator and commitment set are improperly allocated - None - } else { - Some(Self { validators, commitments, id }) - } - } - - /// Return a reference to the vec of validators. - pub fn validators(&self) -> &[AuthorityId] { - &self.validators - } - - /// Return a reference to the vec of commitments. - pub fn commitments(&self) -> &[AuthorityId] { - &self.commitments - } - - /// Return the validator set id. - pub fn id(&self) -> ValidatorSetId { - self.id - } - - /// Return the number of validators in the set. - pub fn len(&self) -> usize { - self.validators.len() - } -} - -/// The index of an authority. -pub type AuthorityIndex = u32; - -/// The Hashing used within MMR. -pub type MmrHashing = Keccak256; -/// The type used to represent an MMR root hash. -pub type MmrRootHash = H256; - -/// A consensus log item for BEEFY. -#[derive(Decode, Encode, TypeInfo)] -pub enum ConsensusLog { - /// The authorities have changed. - #[codec(index = 1)] - AuthoritiesChange(ValidatorSet), - /// Disable the authority with given index. - #[codec(index = 2)] - OnDisabled(AuthorityIndex), - /// MMR root hash. - #[codec(index = 3)] - MmrRoot(MmrRootHash), -} - -/// BEEFY vote message. -/// -/// A vote message is a direct vote created by a BEEFY node on every voting round -/// and is gossiped to its peers. -// TODO: Remove `Signature` generic type, instead get it from `Id::Signature`. -#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] -pub struct VoteMessage { - /// Commit to information extracted from a finalized block - pub commitment: Commitment, - /// Node authority id - pub id: Id, - /// Node signature - pub signature: Signature, -} - -/// Proof of voter misbehavior on a given set id. Misbehavior/equivocation in -/// BEEFY happens when a voter votes on the same round/block for different payloads. -/// Proving is achieved by collecting the signed commitments of conflicting votes. -#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] -pub struct EquivocationProof { - /// The first vote in the equivocation. - pub first: VoteMessage, - /// The second vote in the equivocation. - pub second: VoteMessage, -} - -impl EquivocationProof { - /// Returns the authority id of the equivocator. - pub fn offender_id(&self) -> &Id { - &self.first.id - } - /// Returns the round number at which the equivocation occurred. - pub fn round_number(&self) -> &Number { - &self.first.commitment.block_number - } - /// Returns the set id at which the equivocation occurred. - pub fn set_id(&self) -> ValidatorSetId { - self.first.commitment.validator_set_id - } -} - -/// Check a commitment signature by encoding the commitment and -/// verifying the provided signature using the expected authority id. -pub fn check_commitment_signature( - commitment: &Commitment, - authority_id: &Id, - signature: &::Signature, -) -> bool -where - Id: BeefyAuthorityId, - Number: Clone + Encode + PartialEq, - MsgHash: Hash, -{ - let encoded_commitment = commitment.encode(); - BeefyAuthorityId::::verify(authority_id, signature, &encoded_commitment) -} - -/// Verifies the equivocation proof by making sure that both votes target -/// different blocks and that its signatures are valid. -pub fn check_equivocation_proof( - report: &EquivocationProof::Signature>, -) -> bool -where - Id: BeefyAuthorityId + PartialEq, - Number: Clone + Encode + PartialEq, - MsgHash: Hash, -{ - let first = &report.first; - let second = &report.second; - - // if votes - // come from different authorities, - // are for different rounds, - // have different validator set ids, - // or both votes have the same commitment, - // --> the equivocation is invalid. - if first.id != second.id || - first.commitment.block_number != second.commitment.block_number || - first.commitment.validator_set_id != second.commitment.validator_set_id || - first.commitment.payload == second.commitment.payload - { - return false; - } - - // check signatures on both votes are valid - let valid_first = check_commitment_signature(&first.commitment, &first.id, &first.signature); - let valid_second = - check_commitment_signature(&second.commitment, &second.id, &second.signature); - - return valid_first && valid_second; -} - -/// New BEEFY validator set notification hook. -pub trait OnNewValidatorSet { - /// Function called by the pallet when BEEFY validator set changes. - fn on_new_validator_set( - validator_set: &ValidatorSet, - next_validator_set: &ValidatorSet, - ); -} - -/// No-op implementation of [OnNewValidatorSet]. -impl OnNewValidatorSet for () { - fn on_new_validator_set(_: &ValidatorSet, _: &ValidatorSet) {} -} - -/// An opaque type used to represent the key ownership proof at the runtime API -/// boundary. The inner value is an encoded representation of the actual key -/// ownership proof which will be parameterized when defining the runtime. At -/// the runtime API boundary this type is unknown and as such we keep this -/// opaque representation, implementors of the runtime API will have to make -/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq, TypeInfo)] -pub struct OpaqueKeyOwnershipProof(Vec); -impl OpaqueKeyOwnershipProof { - /// Create a new `OpaqueKeyOwnershipProof` using the given encoded - /// representation. - pub fn new(inner: Vec) -> OpaqueKeyOwnershipProof { - OpaqueKeyOwnershipProof(inner) - } - - /// Try to decode this `OpaqueKeyOwnershipProof` into the given concrete key - /// ownership proof type. - pub fn decode(self) -> Option { - codec::Decode::decode(&mut &self.0[..]).ok() - } -} - -sp_api::decl_runtime_apis! { - /// API necessary for BEEFY voters. - #[api_version(3)] - pub trait BeefyApi where - AuthorityId : Codec + RuntimeAppPublic, - { - /// Return the block number where BEEFY consensus is enabled/started - fn beefy_genesis() -> Option>; - - /// Return the current active BEEFY validator set - fn validator_set() -> Option>; - - /// Submits an unsigned extrinsic to report an equivocation. The caller - /// must provide the equivocation proof and a key ownership proof - /// (should be obtained using `generate_key_ownership_proof`). The - /// extrinsic will be unsigned and should only be accepted for local - /// authorship (not to be broadcast to the network). This method returns - /// `None` when creation of the extrinsic fails, e.g. if equivocation - /// reporting is disabled for the given runtime (i.e. this method is - /// hardcoded to return `None`). Only useful in an offchain context. - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: - EquivocationProof, AuthorityId, ::Signature>, - key_owner_proof: OpaqueKeyOwnershipProof, - ) -> Option<()>; - - /// Generates a proof of key ownership for the given authority in the - /// given set. An example usage of this module is coupled with the - /// session historical module to prove that a given authority key is - /// tied to a given staking identity during a specific session. Proofs - /// of key ownership are necessary for submitting equivocation reports. - /// NOTE: even though the API takes a `set_id` as parameter the current - /// implementations ignores this parameter and instead relies on this - /// method being called at the correct block height, i.e. any point at - /// which the given set id is live on-chain. Future implementations will - /// instead use indexed data through an offchain worker, not requiring - /// older states to be available. - fn generate_key_ownership_proof( - set_id: ValidatorSetId, - authority_id: AuthorityId, - ) -> Option; - - // #[cfg(feature = "bls-experimental")] - /// Return a proof of knowledge for async secret sharing - fn read_share(who: AuthorityId) -> Option>; - - fn submit_unsigned_pulse( - signature_bytes: Vec>, - block_number: NumberFor, - ) -> Option<()>; - } - -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_application_crypto::ecdsa::{self, Public}; - use sp_core::crypto::{Pair, Wraps}; - use sp_crypto_hashing::{blake2_256, keccak_256}; - use sp_runtime::traits::{BlakeTwo256, Keccak256}; - - #[test] - fn validator_set() { - // Empty set not allowed. - assert_eq!(ValidatorSet::::new(vec![], vec![], 0), None); - - let alice = ecdsa::Pair::from_string("//Alice", None).unwrap(); - let alice_stash = ecdsa::Pair::from_string("//AliceStash", None).unwrap(); - let set_id = 0; - let validators = - ValidatorSet::::new(vec![alice.public()], vec![alice_stash.public()], set_id) - .unwrap(); - - assert_eq!(validators.id(), set_id); - assert_eq!(validators.validators(), &vec![alice.public()]); - assert_eq!(validators.commitments(), &vec![alice_stash.public()]); - } - - #[test] - fn ecdsa_beefy_verify_works() { - let msg = &b"test-message"[..]; - let (pair, _) = ecdsa_crypto::Pair::generate(); - - let keccak_256_signature: ecdsa_crypto::Signature = - pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into(); - - 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. - assert!(BeefyAuthorityId::::verify(&pair.public(), &keccak_256_signature, msg)); - assert!(BeefyAuthorityId::::verify( - &pair.public(), - &blake2_256_signature, - msg - )); - // Verification fails if distinct hashing functions are used when signing and verifying. - assert!(!BeefyAuthorityId::::verify(&pair.public(), &blake2_256_signature, msg)); - assert!(!BeefyAuthorityId::::verify( - &pair.public(), - &keccak_256_signature, - msg - )); - - // Other public key doesn't work - let (other_pair, _) = ecdsa_crypto::Pair::generate(); - assert!(!BeefyAuthorityId::::verify( - &other_pair.public(), - &keccak_256_signature, - msg, - )); - assert!(!BeefyAuthorityId::::verify( - &other_pair.public(), - &blake2_256_signature, - msg, - )); - } - - #[test] - // #[cfg(feature = "bls-experimental")] - fn bls_beefy_verify_works() { - let msg = &b"test-message"[..]; - let (pair, _) = bls_crypto::Pair::generate(); - - let signature: bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); - - // Verification works if same hashing function is used when signing and verifying. - assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); - - // Other public key doesn't work - let (other_pair, _) = bls_crypto::Pair::generate(); - assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); - } - - // #[test] - // // #[cfg(feature = "bls-experimental")] - // #[cfg(all(feature = "bls-experimental", feature = "full_crypto"))] - // fn ecdsa_bls_beefy_verify_works() { - // let msg = &b"test-message"[..]; - // let (pair, _) = ecdsa_bls_crypto::Pair::generate(); - - // let signature: ecdsa_bls_crypto::Signature = - // pair.as_inner_ref().sign_with_hasher::(&msg).into(); - - // // Verification works if same hashing function is used when signing and verifying. - // assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); - - // // Verification doesn't work if we verify function provided by pair_crypto implementation - // assert!(!ecdsa_bls_crypto::Pair::verify(&signature, msg, &pair.public())); - - // // Other public key doesn't work - // let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); - // assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); - // } -} diff --git a/primitives/consensus/beefy-etf/src/mmr.rs b/primitives/consensus/beefy-etf/src/mmr.rs deleted file mode 100644 index 5e7d073..0000000 --- a/primitives/consensus/beefy-etf/src/mmr.rs +++ /dev/null @@ -1,265 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! BEEFY + MMR utilities. -//! -//! While BEEFY can be used completely independently as an additional consensus gadget, -//! it is designed around a main use case of bridging standalone networks together. -//! For that use case it's common to use some aggregated data structure (like MMR) to be -//! used in conjunction with BEEFY, to be able to efficiently prove any past blockchain data. -//! -//! This module contains primitives used by Polkadot implementation of the BEEFY+MMR bridge, -//! 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. - -#[cfg(feature = "bls-experimental")] -use crate::bls_crypto::AuthorityId; -#[cfg(not(feature = "bls-experimental"))] -use crate::ecdsa_crypto::AuthorityId; -use crate::{ConsensusLog, MmrRootHash, BEEFY_ENGINE_ID}; -use alloc::vec::Vec; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::{ - generic::OpaqueDigestItemId, - traits::{Block, Header}, -}; - -/// 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 - fn extra_data() -> ExtraData; -} - -/// A default implementation for runtimes. -impl BeefyDataProvider> for () { - fn extra_data() -> Vec { - Vec::new() - } -} - -/// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct MmrLeaf { - /// Version of the leaf format. - /// - /// Can be used to enable future format migrations and compatibility. - /// See [`MmrLeafVersion`] documentation for details. - pub version: MmrLeafVersion, - /// Current block parent number and hash. - pub parent_number_and_hash: (BlockNumber, Hash), - /// A merkle root of the next BEEFY authority set. - pub beefy_next_authority_set: BeefyNextAuthoritySet, - /// Arbitrary extra leaf data to be used by downstream pallets to include custom data in the - /// [`MmrLeaf`] - pub leaf_extra: ExtraData, -} - -/// An MMR leaf versioning scheme. -/// -/// Version is a single byte that consists of two components: -/// - `major` - 3 bits -/// - `minor` - 5 bits -/// -/// Any change in encoding that adds new items to the structure is considered non-breaking, hence -/// only requires an update of `minor` version. Any backward incompatible change (i.e. decoding to a -/// previous leaf format fails) should be indicated with `major` version bump. -/// -/// Given that adding new struct elements in SCALE is backward compatible (i.e. old format can be -/// still decoded, the new fields will simply be ignored). We expect the major version to be bumped -/// very rarely (hopefully never). -#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct MmrLeafVersion(u8); -impl MmrLeafVersion { - /// Create new version object from `major` and `minor` components. - /// - /// Panics if any of the component occupies more than 4 bits. - pub fn new(major: u8, minor: u8) -> Self { - if major > 0b111 || minor > 0b11111 { - panic!("Version components are too big."); - } - let version = (major << 5) + minor; - Self(version) - } - - /// Split the version into `major` and `minor` sub-components. - pub fn split(&self) -> (u8, u8) { - let major = self.0 >> 5; - let minor = self.0 & 0b11111; - (major, minor) - } -} - -/// Details of a BEEFY authority set. -#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BeefyAuthoritySet { - /// Id of the set. - /// - /// Id is required to correlate BEEFY signed commitments with the validator set. - /// Light Client can easily verify that the commitment witness it is getting is - /// produced by the latest validator set. - pub id: crate::ValidatorSetId, - /// Number of validators in the set. - /// - /// Some BEEFY Light Clients may use an interactive protocol to verify only a subset - /// of signatures. We put set length here, so that these clients can verify the minimal - /// number of required signatures. - pub len: u32, - - /// Commitment(s) to BEEFY AuthorityIds. - /// - /// This is used by Light Clients to confirm that the commitments are signed by the correct - /// 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). - /// - /// This could be Merkle Root Hash built from BEEFY ECDSA public keys and/or - /// polynomial commitment to the polynomial interpolating BLS public keys - /// which is used by APK proof based light clients to verify the validity - /// of aggregated BLS keys using APK proofs. - /// Multiple commitments can be tupled together. - pub keyset_commitment: AuthoritySetCommitment, -} - -/// Details of the next BEEFY authority set. -pub type BeefyNextAuthoritySet = BeefyAuthoritySet; - -/// Extract the MMR root hash from a digest in the given header, if it exists. -pub fn find_mmr_root_digest(header: &B::Header) -> Option { - let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - - let filter = |log: ConsensusLog| match log { - ConsensusLog::MmrRoot(root) => Some(root), - _ => None, - }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) -} - -#[cfg(feature = "std")] -pub use mmr_root_provider::MmrRootProvider; -#[cfg(feature = "std")] -mod mmr_root_provider { - use super::*; - use crate::{known_payloads, payload::PayloadProvider, Payload}; - use alloc::sync::Arc; - use core::marker::PhantomData; - use sp_api::ProvideRuntimeApi; - use sp_mmr_primitives::MmrApi; - use sp_runtime::traits::NumberFor; - - /// A [`crate::Payload`] provider where payload is Merkle Mountain Range root hash. - /// - /// Encoded payload contains a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). - pub struct MmrRootProvider { - runtime: Arc, - _phantom: PhantomData, - } - - impl Clone for MmrRootProvider { - fn clone(&self) -> Self { - Self { runtime: self.runtime.clone(), _phantom: PhantomData } - } - } - - impl MmrRootProvider - where - B: Block, - R: ProvideRuntimeApi, - R::Api: MmrApi>, - { - /// Create new BEEFY Payload provider with MMR Root as payload. - pub fn new(runtime: Arc) -> Self { - Self { runtime, _phantom: PhantomData } - } - - /// Simple wrapper that gets MMR root from header digests or from client state. - fn mmr_root_from_digest_or_runtime(&self, header: &B::Header) -> Option { - find_mmr_root_digest::(header).or_else(|| { - self.runtime.runtime_api().mmr_root(header.hash()).ok().and_then(|r| r.ok()) - }) - } - } - - impl PayloadProvider for MmrRootProvider - where - B: Block, - R: ProvideRuntimeApi, - R::Api: MmrApi>, - { - fn payload(&self, header: &B::Header) -> Option { - self.mmr_root_from_digest_or_runtime(header).map(|mmr_root| { - Payload::from_single_entry(known_payloads::MMR_ROOT_ID, mmr_root.encode()) - }) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::H256; - use sp_runtime::{traits::BlakeTwo256, Digest, DigestItem, OpaqueExtrinsic}; - - #[test] - fn should_construct_version_correctly() { - let tests = vec![(0, 0, 0b00000000), (7, 2, 0b11100010), (7, 31, 0b11111111)]; - - for (major, minor, version) in tests { - let v = MmrLeafVersion::new(major, minor); - assert_eq!(v.encode(), vec![version], "Encoding does not match."); - assert_eq!(v.split(), (major, minor)); - } - } - - #[test] - #[should_panic] - fn should_panic_if_major_too_large() { - MmrLeafVersion::new(8, 0); - } - - #[test] - #[should_panic] - fn should_panic_if_minor_too_large() { - MmrLeafVersion::new(0, 32); - } - - #[test] - fn extract_mmr_root_digest() { - type Header = sp_runtime::generic::Header; - type Block = sp_runtime::generic::Block; - let mut header = Header::new( - 1u64, - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - - // verify empty digest shows nothing - assert!(find_mmr_root_digest::(&header).is_none()); - - let mmr_root_hash = H256::random(); - header.digest_mut().push(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_root_hash).encode(), - )); - - // verify validator set is correctly extracted from digest - let extracted = find_mmr_root_digest::(&header); - assert_eq!(extracted, Some(mmr_root_hash)); - } -} diff --git a/primitives/consensus/beefy-etf/src/payload.rs b/primitives/consensus/beefy-etf/src/payload.rs deleted file mode 100644 index bdce517..0000000 --- a/primitives/consensus/beefy-etf/src/payload.rs +++ /dev/null @@ -1,108 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode}; -use scale_info::TypeInfo; -use sp_runtime::traits::Block; - -/// Id of different payloads in the [`crate::Commitment`] data. -pub type BeefyPayloadId = [u8; 2]; - -/// Registry of all known [`BeefyPayloadId`]. -pub mod known_payloads { - use crate::BeefyPayloadId; - - /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. - /// - /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). - pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; - - /// A [`Payload`](super::Payload) identifier for empty ETF payloads. - pub const ETF_SIGNATURE: BeefyPayloadId = *b"ef"; -} - -/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. -/// -/// The idea is to store a vector of SCALE-encoded values with an extra identifier. -/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected -/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only -/// support a subset of possible values. -#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash, TypeInfo)] -pub struct Payload(Vec<(BeefyPayloadId, Vec)>); - -impl Payload { - /// Construct a new payload given an initial value - pub fn from_single_entry(id: BeefyPayloadId, value: Vec) -> Self { - Self(vec![(id, value)]) - } - - /// Returns a raw payload under given `id`. - /// - /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. - pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { - let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; - Some(&self.0[index].1) - } - - /// Returns a decoded payload value under given `id`. - /// - /// In case the value is not there or it cannot be decoded does not match `None` is returned. - pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { - self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) - } - - /// Push a `Vec` with a given id into the payload vec. - /// This method will internally sort the payload vec after every push. - /// - /// Returns self to allow for daisy chaining. - pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { - self.0.push((id, value)); - self.0.sort_by_key(|(id, _)| *id); - self - } -} - -/// Trait for custom BEEFY payload providers. -pub trait PayloadProvider { - /// Provide BEEFY payload if available for `header`. - fn payload(&self, header: &B::Header) -> Option; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn payload_methods_work_as_expected() { - let id1: BeefyPayloadId = *b"hw"; - let msg1: String = "1. Hello World!".to_string(); - let id2: BeefyPayloadId = *b"yb"; - let msg2: String = "2. Yellow Board!".to_string(); - let id3: BeefyPayloadId = *b"cs"; - let msg3: String = "3. Cello Cord!".to_string(); - - let payload = Payload::from_single_entry(id1, msg1.encode()) - .push_raw(id2, msg2.encode()) - .push_raw(id3, msg3.encode()); - - assert_eq!(payload.get_decoded(&id1), Some(msg1)); - assert_eq!(payload.get_decoded(&id2), Some(msg2)); - assert_eq!(payload.get_raw(&id3), Some(&msg3.encode())); - assert_eq!(payload.get_raw(&known_payloads::MMR_ROOT_ID), None); - } -} diff --git a/primitives/consensus/beefy-etf/src/test_utils.rs b/primitives/consensus/beefy-etf/src/test_utils.rs deleted file mode 100644 index 2541d9d..0000000 --- a/primitives/consensus/beefy-etf/src/test_utils.rs +++ /dev/null @@ -1,222 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -// #[cfg(feature = "bls-experimental")] -// use crate::bls_bls_crypto; -use crate::{ - bls_crypto, bls_crypto::AuthorityId as BeefyId, AuthorityIdBound, BeefySignatureHasher, - Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage, -}; -use sp_application_crypto::{AppCrypto, AppPair, RuntimeAppPublic, UncheckedFrom, Wraps}; -use sp_core::{bls377, Pair}; -use sp_runtime::traits::Hash; - -use codec::Encode; -use std::{collections::HashMap, marker::PhantomData}; -use strum::IntoEnumIterator; - -use ark_serialize::CanonicalSerialize; -use ark_std::UniformRand; -use etf_crypto_primitives::{dpss::acss::DoubleSecret, proofs::hashed_el_gamal_sigma::BatchPoK}; -use rand::rngs::OsRng; -use w3f_bls::{DoublePublicKey, DoublePublicKeyScheme, EngineBLS, SerializableToBytes}; - -/// Set of test accounts using [`crate::bls_crypto`] types. -#[allow(missing_docs)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] -pub enum Keyring { - Alice, - Bob, - Charlie, - Dave, - Eve, - Ferdie, - One, - Two, - _Marker(PhantomData), -} - -/// Trait representing BEEFY specific generation and signing behavior of authority id -/// -/// Accepts custom hashing fn for the message and custom convertor fn for the signer. -pub trait BeefySignerAuthority: AppPair { - /// Generate and return signature for `message` using custom hashing `MsgHash` - fn sign_with_hasher(&self, message: &[u8]) -> ::Signature; -} - -// #[cfg(feature = "bls-experimental")] -impl BeefySignerAuthority for ::Pair -where - MsgHash: Hash, - ::Output: Into<[u8; 32]>, -{ - fn sign_with_hasher(&self, message: &[u8]) -> ::Signature { - self.as_inner_ref().sign(&message).into() - } -} - -/// Implement Keyring functionalities generically over AuthorityId -impl Keyring -where - AuthorityId: AuthorityIdBound + From<<::Pair as AppCrypto>::Public>, - ::Pair: BeefySignerAuthority, - ::Signature: - Send + Sync + From<<::Pair as AppCrypto>::Signature>, -{ - /// Sign `msg`. - pub fn sign(&self, msg: &[u8]) -> ::Signature { - let key_pair: ::Pair = self.pair(); - key_pair.sign_with_hasher(&msg).into() - } - - /// Return key pair. - pub fn pair(&self) -> ::Pair { - ::Pair::from_string(self.to_seed().as_str(), None) - .unwrap() - .into() - } - - /// Return public key. - pub fn public(&self) -> AuthorityId { - self.pair().public().into() - } - - /// Return seed string. - pub fn to_seed(&self) -> String { - format!("//{}", self) - } - - /// Get Keyring from public key. - pub fn from_public(who: &AuthorityId) -> Option> { - Self::iter().find(|k| k.public() == *who) - } -} - -lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap, bls_crypto::Pair> = - Keyring::iter().map(|i| (i.clone(), i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap, bls_crypto::Public> = - PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect(); -} - -impl From> for bls_crypto::Pair { - fn from(k: Keyring) -> Self { - k.pair() - } -} - -impl From> for bls377::Pair { - fn from(k: Keyring) -> Self { - k.pair().into() - } -} - -impl From> for bls_crypto::Public { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).cloned().unwrap() - } -} - -/// Create a new `EquivocationProof` based on given arguments. -pub fn test_generate_equivocation_proof( - vote1: (BN, Payload, ValidatorSetId, &Keyring), - vote2: (BN, Payload, ValidatorSetId, &Keyring), -) -> EquivocationProof { - let signed_vote = |block_number: BN, - payload: Payload, - validator_set_id: ValidatorSetId, - keyring: &Keyring| { - let commitment = Commitment { validator_set_id, block_number, payload }; - let signature = keyring.sign(&b"idc".to_vec()); - VoteMessage { commitment, id: keyring.public(), signature } - }; - let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3); - let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3); - EquivocationProof { first, second } -} - -/// Create a new `EquivocationProof` based on given arguments. -pub fn generate_equivocation_proof( - vote1: (u64, Payload, ValidatorSetId, &Keyring), - vote2: (u64, Payload, ValidatorSetId, &Keyring), -) -> EquivocationProof { - let signed_vote = |block_number: u64, - payload: Payload, - validator_set_id: ValidatorSetId, - keyring: &Keyring| { - let commitment = Commitment { validator_set_id, block_number, payload }; - let signature = keyring.sign(&commitment.encode()); - VoteMessage { commitment, id: keyring.public(), signature } - }; - let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3); - let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3); - EquivocationProof { first, second } -} - -/// Helper function to prepare initial secrets and resharing for ETF conensus -/// return a vec of (authority id, resharing, pubkey commitment) along with ibe public key against -/// the master secret -pub fn etf_genesis( - initial_authorities: Vec, -) -> (Vec, Vec<(BeefyId, Vec)>) { - let msk_prime = E::Scalar::rand(&mut OsRng); - let keypair = w3f_bls::KeypairVT::::generate(&mut OsRng); - let msk: E::Scalar = keypair.secret.0; - let double_public: DoublePublicKey = - DoublePublicKey(keypair.into_public_key_in_signature_group().0, keypair.public.0); - - let double_secret = DoubleSecret::(msk, msk_prime); - - let mut double_public_bytes = Vec::new(); - double_public.serialize_compressed(&mut double_public_bytes).unwrap(); - - let genesis_resharing: Vec<(DoublePublicKey, BatchPoK)> = double_secret - .reshare( - &initial_authorities - .iter() - .map(|authority| { - w3f_bls::single::PublicKey::( - w3f_bls::double::DoublePublicKey::::from_bytes(&authority.to_raw_vec()) - .unwrap() - .1, - ) - }) - .collect::>(), - initial_authorities.len() as u8, // threshold = full set of authorities for now - &mut OsRng, - ) - .unwrap(); - - let serialized_resharings = initial_authorities - .iter() - .enumerate() - .map(|(idx, _)| { - let pk = &genesis_resharing[idx].0; - let mut pk_bytes = [0u8; 144]; - pk.serialize_compressed(&mut pk_bytes[..]).unwrap(); - let blspk = bls377::Public::unchecked_from(pk_bytes); - - let pok = &genesis_resharing[idx].1; - let mut bytes = Vec::new(); - pok.serialize_compressed(&mut bytes).unwrap(); - - let beefy_id = BeefyId::from(blspk); - (beefy_id, bytes) - }) - .collect::>(); - (double_public_bytes, serialized_resharings) -} diff --git a/primitives/consensus/beefy-etf/src/witness.rs b/primitives/consensus/beefy-etf/src/witness.rs deleted file mode 100644 index f27660c..0000000 --- a/primitives/consensus/beefy-etf/src/witness.rs +++ /dev/null @@ -1,254 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! Primitives for light, 2-phase interactive verification protocol. -//! -//! Instead of submitting full list of signatures, it's possible to submit first a witness -//! form of [SignedCommitment]. -//! This can later be verified by the client requesting only some (out of all) signatures for -//! verification. This allows lowering the data and computation cost of verifying the -//! signed commitment. - -use crate::commitment::{Commitment, SignedCommitment}; -use alloc::vec::Vec; - -/// A light form of [SignedCommitment]. -/// -/// This is a light ("witness") form of the signed commitment. Instead of containing full list of -/// signatures, which might be heavy and expensive to verify, it only contains a bit vector of -/// validators which signed the original [SignedCommitment] and a merkle root of all signatures. -/// -/// This can be used by light clients for 2-phase interactive verification (for instance for -/// 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 { - /// 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 - - /// 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 -{ - /// Convert [SignedCommitment] into [SignedCommitmentWitness]. - /// - /// This takes a [SignedCommitment], which contains full signatures - /// and converts it into a witness form, which does not contain full signatures, - /// only a bit vector indicating which validators have signed the original [SignedCommitment] - /// and a merkle root of all signatures. - /// - /// Returns the full list of signatures along with the witness. - pub fn from_signed( - signed: SignedCommitment, - aggregator: TSignatureAggregator, - ) -> (Self, Vec>) - where - TSignatureAggregator: FnOnce(&[Option]) -> TSignatureAccumulator, - { - let SignedCommitment { commitment, signatures } = signed; - let signed_by = signatures.iter().map(|s| s.is_some()).collect(); - let signature_accumulator = aggregator(&signatures); - - (Self { commitment, signed_by, signature_accumulator }, signatures) - } -} - -#[cfg(test)] -mod tests { - use sp_core::Pair; - use sp_crypto_hashing::keccak_256; - - use super::*; - use codec::Decode; - - use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads, Payload}; - - #[cfg(feature = "bls-experimental")] - use crate::bls_crypto::Signature as BlsSignature; - - #[cfg(feature = "bls-experimental")] - use w3f_bls::{ - single_pop_aggregator::SignatureAggregatorAssumingPoP, Message, SerializableToBytes, - Signed, TinyBLS381, - }; - - type TestCommitment = Commitment; - - // Types for ecdsa signed commitment. - type TestEcdsaSignedCommitment = SignedCommitment; - type TestEcdsaSignedCommitmentWitness = - SignedCommitmentWitness>>; - - #[cfg(feature = "bls-experimental")] - #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] - struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature); - - // types for commitment containing bls signature along side ecdsa signature - #[cfg(feature = "bls-experimental")] - type TestBlsSignedCommitment = SignedCommitment; - #[cfg(feature = "bls-experimental")] - type TestBlsSignedCommitmentWitness = SignedCommitmentWitness>; - - // The mock signatures are equivalent to the ones produced by the BEEFY keystore - fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) { - let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); - - let msg = keccak_256(b"This is the first message"); - let sig1 = alice.sign_prehashed(&msg); - - let msg = keccak_256(b"This is the second message"); - let sig2 = alice.sign_prehashed(&msg); - - (sig1.into(), sig2.into()) - } - - // Generates mock aggregatable bls signature for generating test commitment - // BLS signatures - #[cfg(feature = "bls-experimental")] - fn mock_bls_signatures() -> (BlsSignature, BlsSignature) { - let alice = sp_core::bls::Pair::from_string("//Alice", None).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() -> TestEcdsaSignedCommitment { - 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 sigs = mock_ecdsa_signatures(); - - SignedCommitment { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)] } - } - - #[cfg(feature = "bls-experimental")] - 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 = ecdsa_signed_commitment(); - - // when - let (witness, signatures) = - TestEcdsaSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); - - // then - assert_eq!(witness.signature_accumulator, signatures); - } - - #[test] - #[cfg(feature = "bls-experimental")] - fn should_convert_dually_signed_commitment_to_witness() { - // given - let signed = ecdsa_and_bls_signed_commitment(); - - // when - let (witness, _signatures) = - // from signed take a function as the aggregator - TestBlsSignedCommitmentWitness::from_signed::<_, _>(signed, |sigs| { - // we are going to aggregate the signatures here - let mut aggregatedsigs: SignatureAggregatorAssumingPoP = - SignatureAggregatorAssumingPoP::new(Message::new(b"", b"mock payload")); - - for sig in sigs { - match sig { - Some(sig) => { - let serialized_sig : Vec = (*sig.1).to_vec(); - aggregatedsigs.add_signature( - &w3f_bls::Signature::::from_bytes( - serialized_sig.as_slice() - ).unwrap() - ); - }, - None => (), - } - } - (&aggregatedsigs).signature().to_bytes() - }); - - // We can't use BlsSignature::try_from because it expected 112Bytes (CP (64) + BLS 48) - // single signature while we are having a BLS aggregated signature corresponding to no CP. - w3f_bls::Signature::::from_bytes(witness.signature_accumulator.as_slice()) - .unwrap(); - } - - #[test] - fn should_encode_and_decode_witness() { - // Given - let signed = ecdsa_signed_commitment(); - let (witness, _) = TestEcdsaSignedCommitmentWitness::from_signed::<_, _>( - signed, - |sigs: &[std::option::Option]| sigs.to_vec(), - ); - - // When - let encoded = codec::Encode::encode(&witness); - let decoded = TestEcdsaSignedCommitmentWitness::decode(&mut &*encoded); - - // Then - assert_eq!(decoded, Ok(witness)); - assert_eq!( - encoded, - array_bytes::hex2bytes_unchecked( - "\ - 046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010\ - 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c\ - 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a8\ - 6cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487b\ - ca2324b6a0046395a71681be3d0c2a00\ - " - ) - ); - } -} diff --git a/primitives/consensus/beefy-etf/test-res/large-raw-commitment b/primitives/consensus/beefy-etf/test-res/large-raw-commitment deleted file mode 100644 index d5dbbe402a88e734367395e5af0305f5a47a0872..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44638 zcmeI)F-t;G7zW^@=#W%8gtJb8lR;zccL^uSp_~*Pt_adlGzHavP;nQep($tzT#6_V zC+DVyK-!$@58T!5x#JxiMDIQ4JMa5sx}C#n)Q;m`>9p66Tjgv>zOw1$`$>26f19{M z$b|5itKZfiZuZBktFyPe#%}HDyuXa*h3m>|Zfp8;GKsb?;#v9kVAvc?s$YBaoyAAz z^Y~?UbpJhizbvkwQ$E0V;CJA^;CbMg=)K_GXnkOfWSwZOY` Date: Tue, 11 Feb 2025 10:55:15 -0600 Subject: [PATCH 5/7] update README.md, update Cargo.toml --- Cargo.lock | 846 ++++++----------------------------------------------- Cargo.toml | 1 - README.md | 4 +- 3 files changed, 87 insertions(+), 764 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2873921..cd84ab9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -407,21 +407,6 @@ dependencies = [ "scale-info", ] -[[package]] -name = "ark-secret-scalar" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf?rev=e9782f9)", - "digest 0.10.7", - "getrandom_or_panic", - "zeroize", -] - [[package]] name = "ark-serialize" version = "0.4.2" @@ -468,33 +453,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "ark-transcript" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "563084372d89271122bd743ef0a608179726f5fad0566008ba55bd0f756489b8" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "digest 0.10.7", - "rand_core 0.6.4", - "sha3", -] - -[[package]] -name = "ark-transcript" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "digest 0.10.7", - "rand_core 0.6.4", - "sha3", -] - [[package]] name = "array-bytes" version = "6.2.3" @@ -842,29 +800,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "bandersnatch_vrfs" -version = "0.0.4" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" -dependencies = [ - "ark-bls12-381", - "ark-ec", - "ark-ed-on-bls12-381-bandersnatch", - "ark-ff", - "ark-serialize", - "ark-std", - "dleq_vrf", - "fflonk", - "merlin", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "ring 0.1.0", - "sha2 0.10.8", - "sp-ark-bls12-381", - "sp-ark-ed-on-bls12-381-bandersnatch", - "zeroize", -] - [[package]] name = "base-x" version = "0.2.11" @@ -1102,21 +1037,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "common" -version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#652286c32f96beb9ce7f5793f5e2c2c923f63b73" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "fflonk", - "getrandom_or_panic", - "rand_core 0.6.4", -] - [[package]] name = "common-path" version = "1.0.0" @@ -1446,22 +1366,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "dleq_vrf" -version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-scale 0.0.12", - "ark-secret-scalar", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ring-vrf?rev=e9782f9)", - "arrayvec", - "zeroize", -] - [[package]] name = "docify" version = "0.2.9" @@ -1609,7 +1513,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.89", @@ -1637,60 +1541,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "etf-crypto-primitives" -version = "0.2.4" -source = "git+http://github.com/ideal-lab5/etf-sdk?branch=w3fbls-migration#c6e61a89b94b57bcbde2293208a2875469f4fc5c" -dependencies = [ - "aes-gcm", - "ark-bls12-377", - "ark-bls12-381", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "array-bytes", - "chacha20poly1305", - "generic-array", - "parity-scale-codec", - "rand_chacha 0.3.1", - "scale-info", - "serde", - "serde_cbor", - "serde_json", - "sha2 0.10.8", - "sha3", - "w3f-bls", -] - -[[package]] -name = "etf-crypto-primitives" -version = "0.2.4" -source = "git+https://github.com/ideal-lab5/etf-sdk.git#cccd3b7ac2a89b2e0551c857620b3090e8c7bd2e" -dependencies = [ - "aes-gcm", - "ark-bls12-377", - "ark-bls12-381", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "array-bytes", - "chacha20poly1305", - "generic-array", - "parity-scale-codec", - "rand_chacha 0.3.1", - "scale-info", - "serde", - "serde_cbor", - "serde_json", - "sha2 0.10.8", - "sha3", - "w3f-bls", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -1758,19 +1608,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "fflonk" -version = "0.1.0" -source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "merlin", -] - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1841,11 +1678,11 @@ dependencies = [ "paste", "scale-info", "serde", - "sp-api 34.0.0", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", "sp-runtime-interface 28.0.0", "sp-storage 21.0.0", "static_assertions", @@ -1886,21 +1723,21 @@ dependencies = [ "serde", "serde_json", "smallvec", - "sp-api 34.0.0", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-crypto-hashing-proc-macro", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", - "sp-metadata-ir 0.7.0", - "sp-runtime 39.0.5", + "sp-io", + "sp-metadata-ir", + "sp-runtime", "sp-staking", - "sp-state-machine 0.43.0", + "sp-state-machine", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-tracing 17.0.1", - "sp-weights 31.0.0", + "sp-weights", "static_assertions", "tt-call", ] @@ -1921,7 +1758,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-crypto-hashing", "syn 2.0.89", ] @@ -1962,12 +1799,12 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-core", + "sp-io", + "sp-runtime", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-version 37.0.0", - "sp-weights 31.0.0", + "sp-version", + "sp-weights", ] [[package]] @@ -2297,12 +2134,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -3883,11 +3714,11 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sp-ark-bls12-381", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-keyring", - "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-keystore", + "sp-runtime", "timelock", "w3f-bls", ] @@ -4074,16 +3905,6 @@ dependencies = [ "spki", ] -[[package]] -name = "polkadot-ckb-merkle-mountain-range" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b44320e5f7ce2c18227537a3032ae5b2c476a7e8eddba45333e1011fc31b92" -dependencies = [ - "cfg-if", - "itertools 0.10.5", -] - [[package]] name = "polkavm-common" version = "0.9.0" @@ -4323,7 +4144,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" dependencies = [ - "heck 0.5.0", + "heck", "itertools 0.12.1", "log", "multimap", @@ -4649,23 +4470,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#652286c32f96beb9ce7f5793f5e2c2c923f63b73" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "ark-transcript 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec", - "blake2", - "common", - "fflonk", -] - [[package]] name = "ring" version = "0.16.20" @@ -5247,29 +5051,6 @@ dependencies = [ "sha1", ] -[[package]] -name = "sp-api" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "hash-db", - "log", - "parity-scale-codec", - "scale-info", - "sp-api-proc-macro 15.0.0", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-metadata-ir 0.6.0", - "sp-runtime 31.0.1", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-trie 29.0.0", - "sp-version 29.0.0", - "thiserror 1.0.69", -] - [[package]] name = "sp-api" version = "34.0.0" @@ -5281,32 +5062,18 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-api-proc-macro 20.0.0", - "sp-core 34.0.0", + "sp-api-proc-macro", + "sp-core", "sp-externalities 0.29.0", - "sp-metadata-ir 0.7.0", - "sp-runtime 39.0.5", + "sp-metadata-ir", + "sp-runtime", "sp-runtime-interface 28.0.0", - "sp-state-machine 0.43.0", - "sp-trie 37.0.0", - "sp-version 37.0.0", + "sp-state-machine", + "sp-trie", + "sp-version", "thiserror 1.0.69", ] -[[package]] -name = "sp-api-proc-macro" -version = "15.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "Inflector", - "blake2", - "expander", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "sp-api-proc-macro" version = "20.0.0" @@ -5322,19 +5089,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-application-crypto" -version = "30.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "sp-application-crypto" version = "38.0.0" @@ -5344,23 +5098,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", -] - -[[package]] -name = "sp-arithmetic" -version = "23.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "scale-info", - "serde", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "static_assertions", + "sp-core", + "sp-io", ] [[package]] @@ -5388,40 +5127,6 @@ dependencies = [ "sp-crypto-ec-utils", ] -[[package]] -name = "sp-ark-ed-on-bls12-381-bandersnatch" -version = "0.4.2" -source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" -dependencies = [ - "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils", -] - -[[package]] -name = "sp-consensus-beefy-etf" -version = "13.0.0" -dependencies = [ - "ark-serialize", - "ark-std", - "array-bytes", - "etf-crypto-primitives 0.2.4 (git+https://github.com/ideal-lab5/etf-sdk.git)", - "lazy_static", - "parity-scale-codec", - "rand 0.8.5", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-io 30.0.0", - "sp-keystore 0.34.0", - "sp-mmr-primitives", - "sp-runtime 31.0.1", - "strum 0.24.1", - "w3f-bls", -] - [[package]] name = "sp-consensus-randomness-beacon" version = "1.0.0-dev" @@ -5442,19 +5147,17 @@ dependencies = [ [[package]] name = "sp-core" -version = "28.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7" dependencies = [ - "ark-serialize", "array-bytes", - "bandersnatch_vrfs", "bitflags 1.3.2", "blake2", "bounded-collections", "bs58", "dyn-clonable", "ed25519-zebra", - "etf-crypto-primitives 0.2.4 (git+http://github.com/ideal-lab5/etf-sdk?branch=w3fbls-migration)", "futures", "hash-db", "hash256-std-hasher", @@ -5475,14 +5178,14 @@ dependencies = [ "secp256k1", "secrecy", "serde", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", + "sp-crypto-hashing", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.29.0", + "sp-runtime-interface 28.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", "ss58-registry", - "substrate-bip39 0.4.7", + "substrate-bip39", "thiserror 1.0.69", "tracing", "w3f-bls", @@ -5490,56 +5193,9 @@ dependencies = [ ] [[package]] -name = "sp-core" -version = "34.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7" -dependencies = [ - "array-bytes", - "bitflags 1.3.2", - "blake2", - "bounded-collections", - "bs58", - "dyn-clonable", - "ed25519-zebra", - "futures", - "hash-db", - "hash256-std-hasher", - "impl-serde 0.4.0", - "itertools 0.11.0", - "k256", - "libsecp256k1", - "log", - "merlin", - "parity-bip39", - "parity-scale-codec", - "parking_lot", - "paste", - "primitive-types 0.12.2", - "rand 0.8.5", - "scale-info", - "schnorrkel", - "secp256k1", - "secrecy", - "serde", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-externalities 0.29.0", - "sp-runtime-interface 28.0.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-storage 21.0.0", - "ss58-registry", - "substrate-bip39 0.6.0", - "thiserror 1.0.69", - "tracing", - "w3f-bls", - "zeroize", -] - -[[package]] -name = "sp-crypto-ec-utils" -version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#a8722784fb36e13c811605bd5631d78643273e24" +name = "sp-crypto-ec-utils" +version = "0.10.0" +source = "git+https://github.com/paritytech/polkadot-sdk#a8722784fb36e13c811605bd5631d78643273e24" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -5553,7 +5209,7 @@ dependencies = [ "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", "ark-scale 0.0.12", - "sp-runtime-interface 24.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-runtime-interface 24.0.0", ] [[package]] @@ -5570,19 +5226,6 @@ dependencies = [ "twox-hash", ] -[[package]] -name = "sp-crypto-hashing" -version = "0.1.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "blake2b_simd", - "byteorder", - "digest 0.10.7", - "sha2 0.10.8", - "sha3", - "twox-hash", -] - [[package]] name = "sp-crypto-hashing-proc-macro" version = "0.1.0" @@ -5590,17 +5233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ "quote", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.89", -] - -[[package]] -name = "sp-crypto-hashing-proc-macro" -version = "0.1.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", + "sp-crypto-hashing", "syn 2.0.89", ] @@ -5615,16 +5248,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-debug-derive" -version = "14.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "sp-debug-derive" version = "14.0.0" @@ -5635,16 +5258,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-externalities" -version = "0.25.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "environmental", - "parity-scale-codec", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "sp-externalities" version = "0.25.0" @@ -5652,7 +5265,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#a8722784fb36e13c811605b dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 19.0.0", ] [[package]] @@ -5675,8 +5288,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde_json", - "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-api", + "sp-runtime", ] [[package]] @@ -5689,37 +5302,10 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime", "thiserror 1.0.69", ] -[[package]] -name = "sp-io" -version = "30.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "bytes", - "docify", - "ed25519-dalek", - "libsecp256k1", - "log", - "parity-scale-codec", - "polkavm-derive", - "rustversion", - "secp256k1", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-keystore 0.34.0", - "sp-runtime-interface 24.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-state-machine 0.35.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-trie 29.0.0", - "tracing", - "tracing-core", -] - [[package]] name = "sp-io" version = "38.0.0" @@ -5735,14 +5321,14 @@ dependencies = [ "polkavm-derive", "rustversion", "secp256k1", - "sp-core 34.0.0", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-core", + "sp-crypto-hashing", "sp-externalities 0.29.0", - "sp-keystore 0.40.0", + "sp-keystore", "sp-runtime-interface 28.0.0", - "sp-state-machine 0.43.0", + "sp-state-machine", "sp-tracing 17.0.1", - "sp-trie 37.0.0", + "sp-trie", "tracing", "tracing-core", ] @@ -5753,20 +5339,9 @@ version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c0e20624277f578b27f44ecfbe2ebc2e908488511ee2c900c5281599f700ab3" dependencies = [ - "sp-core 34.0.0", - "sp-runtime 39.0.5", - "strum 0.26.3", -] - -[[package]] -name = "sp-keystore" -version = "0.34.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "parking_lot", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", + "sp-core", + "sp-runtime", + "strum", ] [[package]] @@ -5777,20 +5352,10 @@ checksum = "0248b4d784cb4a01472276928977121fa39d977a5bb24793b6b15e64b046df42" dependencies = [ "parity-scale-codec", "parking_lot", - "sp-core 34.0.0", + "sp-core", "sp-externalities 0.29.0", ] -[[package]] -name = "sp-metadata-ir" -version = "0.6.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "frame-metadata", - "parity-scale-codec", - "scale-info", -] - [[package]] name = "sp-metadata-ir" version = "0.7.0" @@ -5802,33 +5367,6 @@ dependencies = [ "scale-info", ] -[[package]] -name = "sp-mmr-primitives" -version = "26.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "log", - "parity-scale-codec", - "polkadot-ckb-merkle-mountain-range", - "scale-info", - "serde", - "sp-api 26.0.0", - "sp-core 28.0.0", - "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime 31.0.1", - "thiserror 1.0.69", -] - -[[package]] -name = "sp-panic-handler" -version = "13.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "backtrace", - "lazy_static", - "regex", -] - [[package]] name = "sp-panic-handler" version = "13.0.1" @@ -5839,31 +5377,6 @@ dependencies = [ "regex", ] -[[package]] -name = "sp-runtime" -version = "31.0.1" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "docify", - "either", - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "num-traits", - "parity-scale-codec", - "paste", - "rand 0.8.5", - "scale-info", - "serde", - "simple-mermaid", - "sp-application-crypto 30.0.0", - "sp-arithmetic 23.0.0", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-weights 27.0.0", -] - [[package]] name = "sp-runtime" version = "39.0.5" @@ -5882,34 +5395,15 @@ dependencies = [ "scale-info", "serde", "simple-mermaid", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-weights 31.0.0", + "sp-weights", "tracing", ] -[[package]] -name = "sp-runtime-interface" -version = "24.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "polkavm-derive", - "primitive-types 0.12.2", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime-interface-proc-macro 17.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-storage 19.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-tracing 16.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-wasm-interface 20.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "24.0.0" @@ -5920,12 +5414,12 @@ dependencies = [ "parity-scale-codec", "polkavm-derive", "primitive-types 0.13.1", - "sp-externalities 0.25.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-runtime-interface-proc-macro 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-externalities 0.25.0", + "sp-runtime-interface-proc-macro 17.0.0", "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-wasm-interface 20.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 19.0.0", + "sp-tracing 16.0.0", + "sp-wasm-interface 20.0.0", "static_assertions", ] @@ -5949,19 +5443,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "17.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "Inflector", - "expander", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" @@ -5999,28 +5480,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.5", -] - -[[package]] -name = "sp-state-machine" -version = "0.35.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hash-db", - "log", - "parity-scale-codec", - "parking_lot", - "rand 0.8.5", - "smallvec", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-panic-handler 13.0.0", - "sp-trie 29.0.0", - "thiserror 1.0.69", - "tracing", - "trie-db", + "sp-core", + "sp-runtime", ] [[package]] @@ -6035,10 +5496,10 @@ dependencies = [ "parking_lot", "rand 0.8.5", "smallvec", - "sp-core 34.0.0", + "sp-core", "sp-externalities 0.29.0", - "sp-panic-handler 13.0.1", - "sp-trie 37.0.0", + "sp-panic-handler", + "sp-trie", "thiserror 1.0.69", "tracing", "trie-db", @@ -6050,28 +5511,11 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" -[[package]] -name = "sp-std" -version = "14.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" - [[package]] name = "sp-std" version = "14.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#a8722784fb36e13c811605bd5631d78643273e24" -[[package]] -name = "sp-storage" -version = "19.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "impl-serde 0.4.0", - "parity-scale-codec", - "ref-cast", - "serde", - "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "sp-storage" version = "19.0.0" @@ -6097,17 +5541,6 @@ dependencies = [ "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sp-tracing" -version = "16.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "tracing", - "tracing-core", - "tracing-subscriber 0.3.18", -] - [[package]] name = "sp-tracing" version = "16.0.0" @@ -6131,29 +5564,6 @@ dependencies = [ "tracing-subscriber 0.3.18", ] -[[package]] -name = "sp-trie" -version = "29.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "ahash", - "hash-db", - "lazy_static", - "memory-db", - "nohash-hasher", - "parity-scale-codec", - "parking_lot", - "rand 0.8.5", - "scale-info", - "schnellru", - "sp-core 28.0.0", - "sp-externalities 0.25.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "thiserror 1.0.69", - "tracing", - "trie-db", - "trie-root", -] - [[package]] name = "sp-trie" version = "37.0.0" @@ -6170,7 +5580,7 @@ dependencies = [ "rand 0.8.5", "scale-info", "schnellru", - "sp-core 34.0.0", + "sp-core", "sp-externalities 0.29.0", "thiserror 1.0.69", "tracing", @@ -6178,23 +5588,6 @@ dependencies = [ "trie-root", ] -[[package]] -name = "sp-version" -version = "29.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "impl-serde 0.4.0", - "parity-scale-codec", - "parity-wasm", - "scale-info", - "serde", - "sp-crypto-hashing-proc-macro 0.1.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-runtime 31.0.1", - "sp-std 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", - "sp-version-proc-macro 13.0.0", - "thiserror 1.0.69", -] - [[package]] name = "sp-version" version = "37.0.0" @@ -6206,24 +5599,13 @@ dependencies = [ "parity-wasm", "scale-info", "serde", - "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-runtime 39.0.5", + "sp-crypto-hashing-proc-macro", + "sp-runtime", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-version-proc-macro 14.0.0", + "sp-version-proc-macro", "thiserror 1.0.69", ] -[[package]] -name = "sp-version-proc-macro" -version = "13.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "parity-scale-codec", - "proc-macro2", - "quote", - "syn 2.0.89", -] - [[package]] name = "sp-version-proc-macro" version = "14.0.0" @@ -6236,16 +5618,6 @@ dependencies = [ "syn 2.0.89", ] -[[package]] -name = "sp-wasm-interface" -version = "20.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "impl-trait-for-tuples", - "log", - "parity-scale-codec", -] - [[package]] name = "sp-wasm-interface" version = "20.0.0" @@ -6269,20 +5641,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "sp-weights" -version = "27.0.0" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "bounded-collections", - "parity-scale-codec", - "scale-info", - "serde", - "smallvec", - "sp-arithmetic 23.0.0", - "sp-debug-derive 14.0.0 (git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing)", -] - [[package]] name = "sp-weights" version = "31.0.0" @@ -6294,7 +5652,7 @@ dependencies = [ "scale-info", "serde", "smallvec", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6347,35 +5705,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros 0.24.3", -] - [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.4", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", + "strum_macros", ] [[package]] @@ -6384,25 +5720,13 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", "syn 2.0.89", ] -[[package]] -name = "substrate-bip39" -version = "0.4.7" -source = "git+https://github.com/ideal-lab5/polkadot-sdk.git?branch=testing#0bd1f08ed576063e678539edafdf3a589ff3989e" -dependencies = [ - "hmac 0.12.1", - "pbkdf2", - "schnorrkel", - "sha2 0.10.8", - "zeroize", -] - [[package]] name = "substrate-bip39" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 8538c61..a74a4f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "client/consensus/randomness-beacon", - "primitives/consensus/beefy-etf", "primitives/consensus/randomness-beacon", "pallets/drand" ] diff --git a/README.md b/README.md index 7557d3f..fd00a3a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Various runtime module, primitives, and pallets used by the Ideal Network and pr ## Build -The client and primitives modules should be built with the "bls-experimental" feature flag. +The client and primitives module should be built with the standard cargo build command. -`cargo build --features "bls-experimental"` +`cargo build` From d9c39dea0966a6e80ae8a9fc7c6653b9dfc2eeda Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 13:26:19 -0600 Subject: [PATCH 6/7] fixing formatting issues reoprted by cargo fmt --- README.md | 1 + .../consensus/randomness-beacon/src/gossipsub.rs | 11 ++++------- .../consensus/randomness-beacon/src/types.rs | 15 +++++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index fd00a3a..355b762 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,4 @@ The client and primitives module should be built with the standard cargo build c `cargo build` + \ No newline at end of file diff --git a/client/consensus/randomness-beacon/src/gossipsub.rs b/client/consensus/randomness-beacon/src/gossipsub.rs index 3fd1075..05ce7ae 100644 --- a/client/consensus/randomness-beacon/src/gossipsub.rs +++ b/client/consensus/randomness-beacon/src/gossipsub.rs @@ -61,7 +61,8 @@ pub struct GossipsubState { } impl GossipsubState { - /// Append a new pulse to the pulses vec. It returns Ok() if successful, otherwise gives an error. + /// Append a new pulse to the pulses vec. It returns Ok() if successful, otherwise gives an + /// error. /// * `pulse`: The pulse to append fn add_pulse(&mut self, pulse: Pulse) -> Result<(), Error> { let opaque = pulse.try_into().map_err(|_| Error::SignatureBufferCapacityExceeded)?; @@ -84,12 +85,12 @@ pub struct GossipsubNetwork { impl GossipsubNetwork { /// Build a new gossipsub network. /// It constructs a libp2p [swarm](https://docs.rs/libp2p/latest/libp2p/struct.Swarm.html) - /// where message authenticity requires signatures from the provided key and with a tcp-based transport layer. + /// where message authenticity requires signatures from the provided key and with a tcp-based + /// transport layer. /// /// * `key`: A libp2p keypair /// * `state`: The shared state /// * `gossipsub_config`: A gossipsub config - /// pub fn new( key: &Keypair, state: SharedState, @@ -120,7 +121,6 @@ impl GossipsubNetwork { /// * `topic_str`: The gossipsub topic to subscribe to /// * `peers`: A list of peers to dial /// * `listen_addr`: An address to listen on. If None, then a random local port is assigned. - /// pub async fn run( &mut self, topic_str: &str, @@ -146,9 +146,7 @@ impl GossipsubNetwork { /// Executes until at least `target_count` ConnectionEstablished events /// have been observed. - /// /// * `target_count`: The number of connection established events to observe until it terminates - /// async fn wait_for_peers(&mut self, target_count: usize) { let mut connected_peers = 0; while connected_peers < target_count { @@ -163,7 +161,6 @@ impl GossipsubNetwork { /// and ignores and messages it cannot understand. /// /// * `topic_str`: The gossipsub topic to subscribe to. - /// async fn subscribe(&mut self, topic_str: &str) -> Result<(), Error> { let topic = IdentTopic::new(topic_str); diff --git a/primitives/consensus/randomness-beacon/src/types.rs b/primitives/consensus/randomness-beacon/src/types.rs index a3c3f4d..5285097 100644 --- a/primitives/consensus/randomness-beacon/src/types.rs +++ b/primitives/consensus/randomness-beacon/src/types.rs @@ -39,7 +39,8 @@ pub struct Pulse { } /// An `OpaquePulse` represents a pulse from a beacon using primitive types -/// This struct is used to encode pulses in the runtime, where we obtain an OpaquePulse by converting a Pulse +/// This struct is used to encode pulses in the runtime, where we obtain an OpaquePulse by +/// converting a Pulse #[derive(Clone, Debug, PartialEq, codec::MaxEncodedLen, scale_info::TypeInfo, Encode, Decode)] pub struct OpaquePulse { /// The round of the beacon protocol @@ -74,7 +75,6 @@ impl OpaquePulse { /// Deserialize from a slice /// /// * `data`: The data to attempt to deserialize - /// pub fn deserialize_from_vec(data: &[u8]) -> Result { if data.len() != 56 { return Err(format!( @@ -125,11 +125,10 @@ mod tests { 76, 235, 84, 49, 223, 95, 22, 186, 113, 163, 202, 195, 230, 117, ]; - pub const VALID_SIG: &[u8] = &[ - 146, 37, 87, 193, 37, 144, 182, 61, 73, 122, 248, 242, 242, - 43, 61, 28, 75, 93, 37, 95, 131, 38, 3, 203, 216, 6, 213, 241, 244, 90, 162, 208, 90, 104, - 76, 235, 84, 49, 223, 95, 22, 186, 113, 163, 202, 195, 230, 117, + 146, 37, 87, 193, 37, 144, 182, 61, 73, 122, 248, 242, 242, 43, 61, 28, 75, 93, 37, 95, + 131, 38, 3, 203, 216, 6, 213, 241, 244, 90, 162, 208, 90, 104, 76, 235, 84, 49, 223, 95, + 22, 186, 113, 163, 202, 195, 230, 117, ]; #[test] @@ -184,8 +183,8 @@ mod tests { fn test_signature_point_invalid() { let valid_pulse = valid_pulse(); let mut opaque_pulse: OpaquePulse = valid_pulse.clone().try_into().unwrap(); - // corrup the signature - opaque_pulse.signature = [1;48]; + // corrupt the signature + opaque_pulse.signature = [1; 48]; let result = opaque_pulse.signature_point(); assert!( result.is_err(), From 9d29a970c0f1988282d3e089a9f19cdc2376a367 Mon Sep 17 00:00:00 2001 From: colemanirby Date: Tue, 11 Feb 2025 17:17:10 -0600 Subject: [PATCH 7/7] remove Build section from README.md --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index 355b762..f6e918e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ # Ideal Labs Modules Various runtime module, primitives, and pallets used by the Ideal Network and protocols that leverage timelock-encryption. - -## Build - -The client and primitives module should be built with the standard cargo build command. - -`cargo build` - - \ No newline at end of file