From c67c790dc3223880ce5e941c175fdb7283fce98f Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Mon, 26 Feb 2024 14:39:41 -0500 Subject: [PATCH 01/20] Update to 1.7.0 --- Cargo.toml | 126 +++++---- crates/bls/src/macros.rs | 3 - .../eth-rpc-client/src/beacon_rpc_client.rs | 2 +- crates/eth-rpc-client/src/eth1_rpc_client.rs | 2 +- .../src/execution_block_proof.rs | 2 +- .../hand_made_finality_light_client_update.rs | 2 +- crates/finality-update-verify/src/lib.rs | 2 +- crates/lc-relay-types/src/lib.rs | 4 +- crates/ssz/tests/tests.rs | 7 +- pallets/eth2-light-client/src/mock.rs | 3 +- pallets/light-proposals/Cargo.toml | 82 ------ pallets/light-proposals/src/lib.rs | 256 ------------------ pallets/light-proposals/src/mock.rs | 203 -------------- pallets/light-proposals/src/tests.rs | 162 ----------- pallets/light-verifier/Cargo.toml | 2 - pallets/light-verifier/src/verify.rs | 2 +- rust-toolchain.toml | 2 +- 17 files changed, 75 insertions(+), 787 deletions(-) delete mode 100644 pallets/light-proposals/Cargo.toml delete mode 100644 pallets/light-proposals/src/lib.rs delete mode 100644 pallets/light-proposals/src/mock.rs delete mode 100644 pallets/light-proposals/src/tests.rs diff --git a/Cargo.toml b/Cargo.toml index f1420feb..e5dcc69d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ funty = "2.0.0" anyhow = "1.0" typed-builder = "0.16.0" log = { version = "0.4", default-features = false } -serde_json = { version = "1.0.74", default-features = false } +serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } serde = { version = "1.0", features = ["derive"], default-features = false } reqwest = { version = "0.11", features = ["blocking", "json"] } clap = { version = "4.0.9", features = ["derive"] } @@ -77,14 +77,12 @@ zeroize = { version = "1.4.2", features = [ ], default-features = false } subxt = "0.29.0" -webb-relayer-utils = { git = "https://github.com/webb-tools/relayer.git" } -webb-relayer-types = { git = "https://github.com/webb-tools/relayer.git" } webb = { version = "0.7.3", default-features = false, features = [ "evm-runtime", "substrate-runtime", ]} -webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } +webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } types = { git = "https://github.com/webb-tools/lighthouse.git", rev="ef72e752eaf45f4b7eb64dd8dbb0fe088f955df8" } merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git", rev="ef72e752eaf45f4b7eb64dd8dbb0fe088f955df8" } @@ -92,75 +90,75 @@ tree_hash = { version = "0.5.0", features = ["arbitrary"], default-features = fa ethereum_hashing = { version = "1.0.0-beta.2", default-features = false } ethereum_ssz = { version = "0.5.0", features = ["arbitrary"], default-features = false } -sc-cli = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-offchain = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-core = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-executor = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-network = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-service = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-keystore = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-transaction-pool = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-transaction-pool-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-consensus-aura = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-consensus-aura = { default-features = false, version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-consensus-grandpa = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-consensus-grandpa = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-client-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-io = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-timestamp = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-inherents = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-std = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-system = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-support = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-staking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-balances = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-grandpa = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-indices = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-session = { version = "4.0.0-dev", features = ["historical"], default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-sudo = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-timestamp = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-utility = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-block-builder = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-offchain = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-session = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-staking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-transaction-pool = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-version = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-executive = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-try-runtime = { version = "0.10.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +sc-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-offchain = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-core = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-executor = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-network = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-telemetry = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-keystore = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-consensus-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-consensus-grandpa = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-client-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-io = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-inherents = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-std = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-system = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-support = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-staking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-transaction-payment = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-balances = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-grandpa = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-indices = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-session = { features = ["historical"], default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-staking-reward-curve = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-sudo = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-timestamp = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-utility = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-block-builder = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-offchain = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-session = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-staking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-transaction-pool = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-version = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-executive = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-try-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } -pallet-aura = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-bags-list = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +pallet-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-bags-list = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-election-provider-support = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-election-provider-multi-phase = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } # These dependencies are used for the node template's RPCs jsonrpsee = { version = "0.16.2", default-features = false } -sc-rpc = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } -sc-rpc-api = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sp-blockchain = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -sc-basic-authorship = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -substrate-frame-rpc-system = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-transaction-payment-rpc = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0", default-features = false } +sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sc-basic-authorship = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } # Used for the node template's RPCs -frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +frame-system-rpc-runtime-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +pallet-transaction-payment-rpc-runtime-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } # These dependencies are used for runtime benchmarking -frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-benchmarking-cli = { version = "4.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } -try-runtime-cli = { version = "0.10.0-dev", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +frame-system-benchmarking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +try-runtime-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } # local deps pallet-eth2-light-client = { path = "./pallets/eth2-light-client", default-features = false } diff --git a/crates/bls/src/macros.rs b/crates/bls/src/macros.rs index 601c0989..dc59f990 100644 --- a/crates/bls/src/macros.rs +++ b/crates/bls/src/macros.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "std")] -pub use eth2_serde_utils::hex as hex_encode; - /// Contains the functions required for a `TreeHash` implementation. /// /// Does not include the `Impl` section since it gets very complicated when it comes to generics. diff --git a/crates/eth-rpc-client/src/beacon_rpc_client.rs b/crates/eth-rpc-client/src/beacon_rpc_client.rs index 71c3046e..a5a006f5 100644 --- a/crates/eth-rpc-client/src/beacon_rpc_client.rs +++ b/crates/eth-rpc-client/src/beacon_rpc_client.rs @@ -606,7 +606,7 @@ mod tests { const TIMEOUT_STATE_SECONDS: u64 = 1000; fn get_test_config() -> ConfigForTests { - ConfigForTests::load_from_toml("config_for_tests.toml".try_into().unwrap()) + ConfigForTests::load_from_toml("config_for_tests.toml".into()) } #[test] diff --git a/crates/eth-rpc-client/src/eth1_rpc_client.rs b/crates/eth-rpc-client/src/eth1_rpc_client.rs index 7361a4ab..7c206805 100644 --- a/crates/eth-rpc-client/src/eth1_rpc_client.rs +++ b/crates/eth-rpc-client/src/eth1_rpc_client.rs @@ -76,7 +76,7 @@ mod tests { use crate::{config_for_tests::ConfigForTests, eth1_rpc_client::Eth1RPCClient}; fn get_test_config() -> ConfigForTests { - ConfigForTests::load_from_toml("config_for_tests.toml".try_into().unwrap()) + ConfigForTests::load_from_toml("config_for_tests.toml".into()) } #[tokio::test] diff --git a/crates/eth-rpc-client/src/execution_block_proof.rs b/crates/eth-rpc-client/src/execution_block_proof.rs index 21213873..60604fcc 100644 --- a/crates/eth-rpc-client/src/execution_block_proof.rs +++ b/crates/eth-rpc-client/src/execution_block_proof.rs @@ -148,7 +148,7 @@ mod tests { const TIMEOUT_STATE_SECONDS: u64 = 1000; fn get_test_config() -> ConfigForTests { - ConfigForTests::load_from_toml("config_for_tests.toml".try_into().unwrap()) + ConfigForTests::load_from_toml("config_for_tests.toml".into()) } #[test] diff --git a/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs b/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs index 4f80cae6..5c5cacd7 100644 --- a/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs +++ b/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs @@ -334,7 +334,7 @@ mod tests { const TIMEOUT_STATE_SECONDS: u64 = 1000000; fn get_test_config() -> ConfigForTests { - ConfigForTests::load_from_toml("config_for_tests.toml".try_into().unwrap()) + ConfigForTests::load_from_toml("config_for_tests.toml".into()) } fn cmp_light_client_updates( diff --git a/crates/finality-update-verify/src/lib.rs b/crates/finality-update-verify/src/lib.rs index 408cda59..918d19f9 100644 --- a/crates/finality-update-verify/src/lib.rs +++ b/crates/finality-update-verify/src/lib.rs @@ -88,7 +88,7 @@ mod tests { use eth_types::eth2::{LightClientUpdate, SyncCommittee}; fn get_config() -> ConfigForTests { - ConfigForTests::load_from_toml("config_for_tests.toml".try_into().unwrap()) + ConfigForTests::load_from_toml("config_for_tests.toml".into()) } #[test] diff --git a/crates/lc-relay-types/src/lib.rs b/crates/lc-relay-types/src/lib.rs index 746ec6ac..e718513d 100644 --- a/crates/lc-relay-types/src/lib.rs +++ b/crates/lc-relay-types/src/lib.rs @@ -22,7 +22,7 @@ impl WebbRetryClient { let err; { - let resp = self.inner.get(url.clone()).send().await; + let resp = self.inner.get(url).send().await; match resp { Ok(val) => return Ok(val.text().await?), Err(err_) => err = err_, @@ -47,7 +47,7 @@ impl WebbRetryClient { let err; { - let resp = self.inner.post(url.clone()).json(&body).send().await; + let resp = self.inner.post(url).json(&body).send().await; match resp { Ok(val) => return Ok(val.text().await?), Err(err_) => err = err_, diff --git a/crates/ssz/tests/tests.rs b/crates/ssz/tests/tests.rs index e2249db2..37df1377 100644 --- a/crates/ssz/tests/tests.rs +++ b/crates/ssz/tests/tests.rs @@ -100,8 +100,7 @@ mod round_trip { FixedLen { a: 1, b: 0, c: 1 }, ]; - let expected_encodings = vec![ - // | u16--| u64----------------------------| u32----------| + let expected_encodings = [ vec![00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00], vec![01, 00, 01, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00], vec![01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00], @@ -194,9 +193,7 @@ mod round_trip { VariableLen { a: 1, b: vec![0, 1, 2], c: 1 }, ]; - let expected_encodings = vec![ - // 00..................................09 - // | u16--| vec offset-----| u32------------| vec payload --------| + let expected_encodings = [ vec![00, 00, 10, 00, 00, 00, 00, 00, 00, 00], vec![01, 00, 10, 00, 00, 00, 01, 00, 00, 00, 00, 00], vec![01, 00, 10, 00, 00, 00, 01, 00, 00, 00, 00, 00, 01, 00, 02, 00], diff --git a/pallets/eth2-light-client/src/mock.rs b/pallets/eth2-light-client/src/mock.rs index 12f68606..b4c1ad09 100644 --- a/pallets/eth2-light-client/src/mock.rs +++ b/pallets/eth2-light-client/src/mock.rs @@ -52,6 +52,7 @@ impl system::Config for Test { type SS58Prefix = SS58Prefix; type SystemWeightInfo = (); type Version = (); + type RuntimeTask = (); } parameter_types! { @@ -68,10 +69,10 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type FreezeIdentifier = (); - type MaxHolds = (); type MaxFreezes = (); type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = (); } parameter_types! { diff --git a/pallets/light-proposals/Cargo.toml b/pallets/light-proposals/Cargo.toml deleted file mode 100644 index 68affbc0..00000000 --- a/pallets/light-proposals/Cargo.toml +++ /dev/null @@ -1,82 +0,0 @@ -[package] -name = "pallet-light-proposals" -version = "0.1.0" -edition = "2021" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] - -eth-types = { path = "../../crates/eth-types", default-features = false, features = ["eth2"] } -eth2-ssz = { package = "webb-eth2-ssz", path = "../../crates/ssz", default-features = false } -merkle-proof = { package = "webb-merkle-proof", path = "../../crates/merkle-proof", default-features = false } -bls = { package = "webb-bls", path = "../../crates/bls", default-features = false } -tree-hash = { package = "webb-tree-hash", path = "../../crates/tree-hash", default-features = false } -tree-hash-derive = { package = "webb-tree-hash-derive", path = "../../crates/tree-hash-derive", default-features = false } -consensus = { package = "webb-consensus-types", path = "../../crates/consensus-types", default-features = false } - -frame-support = { workspace = true, default-features = false } -frame-system = { workspace = true, default-features = false } -pallet-balances = { workspace = true, default-features = false } -sp-runtime = { workspace = true, default-features = false } -sp-std = { workspace = true, default-features = false } -sp-core = { workspace = true, default-features = false } - -log = { workspace = true, default-features = false } -serde = { workspace = true, optional = true, default-features = false } -codec = { workspace = true, features = ["derive", "max-encoded-len"] } -scale-info = { workspace = true, default-features = false } -webb-proposals = { workspace = true, default-features = false, features = ["evm", "substrate"] } -ethereum-types = { workspace = true, default-features = false } -derive_more = { workspace = true } -rlp = { workspace = true, default-features = false } -rlp-derive = { workspace = true, default-features = false } -tiny-keccak = { workspace = true, default-features = false } -bitvec = { workspace = true, features = ["atomic", "alloc"] } -hex = { workspace = true } -webb-light-client-primitives = { workspace = true } -dkg-runtime-primitives = { git = "https://github.com/webb-tools/dkg-substrate.git", branch = "master", default-features = false } -pallet-bridge-registry = { git = "https://github.com/webb-tools/dkg-substrate.git", branch = "master", default-features = false } -webb = { workspace = true, default-features = false } - -[dev-dependencies] -anyhow = { workspace = true } -lazy_static = { workspace = true } -serde_json = { workspace = true } -eth2-pallet-init = { package = "webb-eth2-pallet-init", path = "../../crates/eth2-pallet-init" } -async-trait = { workspace = true } -pallet-eth2-light-client = { workspace = true, features = ["testing"] } - -[features] -default = ["std"] -std = [ - "serde/std", - "codec/std", - "scale-info/std", - "webb-proposals/std", - "ethereum-types/std", - "rlp/std", - "bitvec/std", - "frame-support/std", - "frame-system/std", - "pallet-balances/std", - "sp-runtime/std", - "sp-std/std", - "sp-core/std", - "hex/std", - "dkg-runtime-primitives/std", - "pallet-bridge-registry/std", - "pallet-eth2-light-client/std", - - # Local dependencies - "bls/std", - "consensus/std", - "eth-types/std", - "eth2-ssz/std", - "tree-hash/std", - "merkle-proof/std", - "webb-light-client-primitives/std" -] - -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/light-proposals/src/lib.rs b/pallets/light-proposals/src/lib.rs deleted file mode 100644 index 23acf222..00000000 --- a/pallets/light-proposals/src/lib.rs +++ /dev/null @@ -1,256 +0,0 @@ -// This file is part of Webb. -// Implementations are Substrate adaptations of the Rainbow Bridge. -// https://github.com/aurora-is-near/rainbow-bridge - -// Copyright (C) 2022 Webb Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later - -// 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 . - -// Ensure we're `no_std` when compiling for Wasm. -#![cfg_attr(not(feature = "std"), no_std)] -#![feature(slice_pattern)] -#![allow(unused)] - -use dkg_runtime_primitives::{ - ProposalHandlerTrait, -}; -use frame_support::{pallet_prelude::DispatchError, traits::Get}; -pub use pallet::*; -use scale_info::TypeInfo; -use sp_std::{convert::TryInto, prelude::*}; - -use webb::evm::{ - contract::protocol_solidity::variable_anchor::v_anchor_contract, ethers::contract::EthCall, -}; -use webb_light_client_primitives::{types::LightProposalInput, LEAF_INDEX_KEY, MERKLE_ROOT_KEY}; -use webb_proposals::{evm::AnchorUpdateProposal, Nonce, TypedChainId, FunctionSignature, ResourceId, ProposalHeader, ProposalKind, Proposal}; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -#[frame_support::pallet] -pub mod pallet { - use core::fmt::Debug; - -use super::*; - - use dkg_runtime_primitives::ProposalHandlerTrait; - - use frame_support::{ - dispatch::DispatchResultWithPostInfo, - pallet_prelude::{ValueQuery, *}, - }; - use frame_system::pallet_prelude::*; - use webb_light_client_primitives::{ - traits::{LightClientHandler, ProofVerifier}, - types::LightProposalInput, - }; - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(_); - - #[pallet::config] - /// The module configuration trait. - pub trait Config: frame_system::Config + pallet_bridge_registry::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Light client interface for the pallet - type LightClient: LightClientHandler; - - /// Storage proof verifier for the pallt - type ProofVerifier: ProofVerifier; - - /// Proposer handler trait - type ProposalHandler: ProposalHandlerTrait< - MaxProposalLength = ::MaxProposalLength, - >; - - /// Max length of submitted proof - #[pallet::constant] - type MaxProofSize: Get + TypeInfo + Clone + Debug + PartialEq + Eq; - - /// Max length of a proposal - #[pallet::constant] - type MaxProposalLength: Get - + Debug - + Clone - + Eq - + PartialEq - + PartialOrd - + Ord - + TypeInfo; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - ProposalSubmitted { proposal: LightProposalInput }, - } - - #[pallet::storage] - #[pallet::getter(fn resource_id_to_nonce)] - /// Mapping of resource to nonce - pub type ResourceIdToNonce = StorageMap<_, Blake2_256, ResourceId, u32, ValueQuery>; - - #[pallet::error] - pub enum Error { - /// Cannot fetch bridge details - CannotFetchBridgeDetails, - /// Cannot fetch bridge metadata - CannotFetchBridgeMetadata, - /// Proof verification failed - ProofVerificationFailed, - } - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().reads_writes(1,1))] - pub fn submit_proposal( - origin: OriginFor, - proposal: LightProposalInput, - ) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - // validate the block header against light client storage - T::LightClient::verify_block_header_exists( - proposal.block_header.clone(), - proposal.resource_id.typed_chain_id(), - )?; - - // validate the merkle proofs - T::ProofVerifier::verify_storage_proof( - proposal.clone().block_header, - MERKLE_ROOT_KEY.to_vec(), - proposal.clone().merkle_root_proof.to_vec(), - ) - .map_err(|_| Error::::ProofVerificationFailed)?; - - T::ProofVerifier::verify_storage_proof( - proposal.clone().block_header, - LEAF_INDEX_KEY.to_vec(), - proposal.clone().leaf_index_proof.to_vec(), - ) - .map_err(|_| Error::::ProofVerificationFailed)?; - - // prepare the proposals to all linked bridges - Self::submit_anchor_update_proposals(proposal.clone())?; - - Ok(().into()) - } - } -} - -impl Pallet { - /// Submits anchor update proposals for all registered bridges from bridge registry - /// - /// This function takes a `TypedChainId` representing the chain ID and a `LightProposalInput` - /// type `proposal` containing the proposal details. - /// - /// The function iterates through all registered bridges on the chain and creates an anchor - /// update proposal for each one. - /// - /// # Arguments - /// - /// * `typed_chain_id` - The typed chain ID. - /// * `proposal` - A `LightProposalInput` containing the details of the proposal. - /// - /// # Errors - /// - /// Returns a `DispatchError` if there was an issue during proposal submission. - pub fn submit_anchor_update_proposals( - proposal: LightProposalInput, - ) -> Result<(), DispatchError> { - let src_resource_id = proposal.resource_id; - - // fetch bridge index for source_resource_id - let bridge_index = pallet_bridge_registry::ResourceToBridgeIndex::::get(src_resource_id) - .ok_or(Error::::CannotFetchBridgeDetails)?; - - // get all connected resource_ids - let bridge_metadata = pallet_bridge_registry::Bridges::::get(bridge_index) - .ok_or(Error::::CannotFetchBridgeMetadata)?; - - for resource_id in bridge_metadata.resource_ids.iter() { - // create AUP for resource_id - Self::create_and_submit_anchor_update_proposal( - proposal.clone(), - src_resource_id, - *resource_id, - )?; - } - - // emit event - Self::deposit_event(Event::ProposalSubmitted { proposal: proposal.clone() }); - - Ok(()) - } - - /// Creates and submits an anchor update proposal. - /// - /// This function takes a `LightProposalInput` type `proposal`, representing the proposal - /// details, `src_resource_id` representing the source resource ID, and `target_resource_id` - /// representing the target resource ID. - /// - /// # Arguments - /// - /// * `proposal` - A `LightProposalInput` containing the details of the proposal. - /// * `src_resource_id` - The resource ID of the source. - /// * `target_resource_id` - The resource ID of the target. - /// - /// # Errors - /// - /// Returns a `DispatchError` if there was an issue during proposal submission. - pub fn create_and_submit_anchor_update_proposal( - proposal: LightProposalInput, - src_resource_id: ResourceId, - target_resource_id: ResourceId, - ) -> Result<(), DispatchError> { - // get the nonce used for target resrouce id - let nonce = ResourceIdToNonce::::get(target_resource_id); - // update the nonce - ResourceIdToNonce::::insert(target_resource_id, nonce.saturating_add(1u32)); - let function_signature_bytes = v_anchor_contract::UpdateEdgeCall::selector(); - - // prep the proposal - let proposal = AnchorUpdateProposal::new( - ProposalHeader::new( - target_resource_id, - FunctionSignature::from(function_signature_bytes), - nonce.into(), - ), - proposal.merkle_root, - src_resource_id, - ); - - let unsigned_anchor_update_proposal: Proposal = Proposal::Unsigned { - kind: ProposalKind::AnchorUpdate, - data: proposal.encode(), - }; - - // submit the proposal - T::ProposalHandler::handle_unsigned_proposal(unsigned_anchor_update_proposal)?; - - Ok(()) - } -} diff --git a/pallets/light-proposals/src/mock.rs b/pallets/light-proposals/src/mock.rs deleted file mode 100644 index 146f1e8a..00000000 --- a/pallets/light-proposals/src/mock.rs +++ /dev/null @@ -1,203 +0,0 @@ -use super::*; -use crate as pallet_light_proposals; - -use codec::{Decode, Encode}; -use consensus::network_config::{Network, NetworkConfig}; - -use dkg_runtime_primitives::{SignedProposalBatch, TypedChainId}; -use eth_types::BlockHeader; -use frame_support::{ensure, pallet_prelude::DispatchResult, parameter_types, sp_io, PalletId}; -use frame_system as system; -use scale_info::TypeInfo; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, ConstU32, IdentifyAccount, IdentityLookup, Verify}, - AccountId32, BuildStorage, MultiSignature, -}; -use sp_std::convert::{TryFrom, TryInto}; -use webb_light_client_primitives::traits::ProofVerifier; - -pub type Signature = MultiSignature; -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; - -// Configure a mock runtime to test the pallet. -frame_support::construct_runtime!( - pub enum Test { - System: frame_system, - Balances: pallet_balances, - BridgeRegistry: pallet_bridge_registry, - Eth2Client: pallet_eth2_light_client, - LightProposals: pallet_light_proposals - } -); - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - -impl system::Config for Test { - type AccountData = pallet_balances::AccountData; - type AccountId = AccountId; - type BaseCallFilter = frame_support::traits::Everything; - type BlockHashCount = BlockHashCount; - type BlockLength = (); - type Nonce = u64; - type Block = frame_system::mocking::MockBlock; - type BlockWeights = (); - type RuntimeCall = RuntimeCall; - type DbWeight = (); - type RuntimeEvent = RuntimeEvent; - type Hash = H256; - type Hashing = BlakeTwo256; - type Lookup = IdentityLookup; - type MaxConsumers = frame_support::traits::ConstU32<16>; - type OnKilledAccount = (); - type OnNewAccount = (); - type OnSetCode = (); - type RuntimeOrigin = RuntimeOrigin; - type PalletInfo = PalletInfo; - type SS58Prefix = SS58Prefix; - type SystemWeightInfo = (); - type Version = (); -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} - -impl pallet_balances::Config for Test { - type AccountStore = System; - type Balance = u128; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxHolds = (); - type MaxFreezes = (); - type WeightInfo = (); - type RuntimeHoldReason = RuntimeHoldReason; -} - -parameter_types! { - #[derive(serde::Serialize, serde::Deserialize)] - pub const MaxAdditionalFields: u32 = 5; - #[derive(serde::Serialize, serde::Deserialize)] - pub const MaxResources: u32 = 32; - pub const StoragePricePerByte: u128 = 1; - pub const Eth2ClientPalletId: PalletId = PalletId(*b"py/eth2c"); -} - -impl pallet_eth2_light_client::Config for Test { - type RuntimeEvent = RuntimeEvent; - type StoragePricePerByte = StoragePricePerByte; - type PalletId = Eth2ClientPalletId; - type Currency = Balances; -} - -parameter_types! { - #[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, scale_info::TypeInfo, Ord, PartialOrd)] - pub const MaxProposalLength : u32 = 10_000; -} - -impl pallet_bridge_registry::Config for Test { - type RuntimeEvent = RuntimeEvent; - type BridgeIndex = u32; - type MaxAdditionalFields = MaxAdditionalFields; - type MaxResources = MaxResources; - type ForceOrigin = frame_system::EnsureRoot; - type MaxProposalLength = MaxProposalLength; - type WeightInfo = (); -} - -pub struct MockStorageProofVerifier; - -impl ProofVerifier for MockStorageProofVerifier { - fn verify_storage_proof( - _header: BlockHeader, - _key: Vec, - proof: Vec>, - ) -> Result { - // test case - ensure!(proof != vec![vec![123]], Error::::ProofVerificationFailed); - Ok(true) - } -} - -pub struct MockProposalHandler; - -impl ProposalHandlerTrait for MockProposalHandler { - type BatchId = u32; - type MaxProposalLength = MaxProposalLength; - type MaxProposals = ConstU32<100>; - type MaxSignatureLen = ConstU32<100>; - - fn handle_unsigned_proposal(_proposal: Proposal) -> DispatchResult { - Ok(()) - } - - fn handle_signed_proposal_batch( - _prop: SignedProposalBatch< - Self::BatchId, - Self::MaxProposalLength, - Self::MaxProposals, - Self::MaxSignatureLen, - >, - ) -> DispatchResult { - Ok(()) - } -} - -parameter_types! { - #[derive(serde::Serialize, serde::Deserialize, Eq, PartialEq, Debug, Clone, Encode, Decode, TypeInfo)] - pub const MaxProofSize: u32 = 50; -} - -impl pallet_light_proposals::Config for Test { - type RuntimeEvent = RuntimeEvent; - type LightClient = Eth2Client; - type ProofVerifier = MockStorageProofVerifier; - type ProposalHandler = MockProposalHandler; - type MaxProofSize = MaxProofSize; - type MaxProposalLength = MaxProposalLength; -} - -// Build genesis storage according to the mock runtime. -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let _ = pallet_balances::GenesisConfig:: { - balances: vec![ - (AccountId32::new([1u8; 32]), 10u128.pow(18)), - (AccountId32::new([2u8; 32]), 20u128.pow(18)), - (AccountId32::new([3u8; 32]), 30u128.pow(18)), - ], - } - .assimilate_storage(&mut storage); - let _ = pallet_eth2_light_client::GenesisConfig:: { - phantom: Default::default(), - networks: vec![ - ( - // Mainnet - TypedChainId::Evm(1), - NetworkConfig::new(&Network::Mainnet), - ), - ( - // Goerli - TypedChainId::Evm(5), - NetworkConfig::new(&Network::Goerli), - ), - ], - } - .assimilate_storage(&mut storage); - - let _ = pallet_bridge_registry::GenesisConfig:: { - phantom: Default::default(), - bridges: vec![], - } - .assimilate_storage(&mut storage); - - storage.into() -} diff --git a/pallets/light-proposals/src/tests.rs b/pallets/light-proposals/src/tests.rs deleted file mode 100644 index c9bad1d8..00000000 --- a/pallets/light-proposals/src/tests.rs +++ /dev/null @@ -1,162 +0,0 @@ -#![allow(clippy::unwrap_used)] -use crate::{mock::*, Error, LightProposalInput, Proposal, ProposalKind, ResourceId}; -use dkg_runtime_primitives::{traits::OnSignedProposal, TypedChainId}; -use ethereum_types::Address; -use frame_support::{assert_err, assert_ok, bounded_vec}; -use lazy_static::lazy_static; -use pallet_bridge_registry::{types::BridgeMetadata, Bridges, ResourceToBridgeIndex}; -use pallet_eth2_light_client::tests::{get_test_context, submit_and_check_execution_headers}; -use sp_runtime::AccountId32; -use webb_proposals::{self, evm, FunctionSignature, Nonce, ProposalHeader, TargetSystem}; - -pub const GOERLI_CHAIN: TypedChainId = TypedChainId::Evm(5); -pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); - -lazy_static! { - static ref GOERLI_RESOURCE_ID: ResourceId = - ResourceId::new(TargetSystem::new_contract_address(Address::from([0; 20])), GOERLI_CHAIN); -} - -// setup bridge registry pallets with defaults -fn setup_bridge_registry() { - let target_chain = webb_proposals::TypedChainId::Evm(1); - let target_system = webb_proposals::TargetSystem::new_contract_address([1u8; 20]); - let target_resource_id = webb_proposals::ResourceId::new(target_system, target_chain); - // Create src info - let src_chain = GOERLI_CHAIN; - let src_target_system = webb_proposals::TargetSystem::new_contract_address([0u8; 20]); - let src_resource_id = webb_proposals::ResourceId::new(src_target_system, src_chain); - // Create mocked signed EVM anchor update proposals - let proposal = evm::AnchorUpdateProposal::new( - ProposalHeader::new(target_resource_id, FunctionSignature([0u8; 4]), Nonce(1)), - [1u8; 32], - src_resource_id, - ); - let signed_proposal = Proposal::Signed { - kind: ProposalKind::AnchorUpdate, - data: proposal.into_bytes().to_vec().try_into().unwrap(), - signature: vec![].try_into().unwrap(), - }; - // Handle signed proposal - assert_ok!(BridgeRegistry::on_signed_proposal(signed_proposal)); - // Verify the storage system updates correctly - assert_eq!(ResourceToBridgeIndex::::get(target_resource_id), Some(1)); - assert_eq!(ResourceToBridgeIndex::::get(src_resource_id), Some(1)); - assert_eq!( - Bridges::::get(1).unwrap(), - BridgeMetadata { - resource_ids: bounded_vec![src_resource_id, target_resource_id], - info: Default::default() - } - ); -} - -#[test] -fn test_light_light_proposal_flow() { - new_test_ext().execute_with(|| { - // setup bridge registry with defaults - setup_bridge_registry(); - - // prep light client pallet - let (headers, updates, _init_input) = get_test_context(None); - assert_ok!(Eth2Client::submit_beacon_chain_light_client_update( - RuntimeOrigin::signed(ALICE), - GOERLI_CHAIN, - updates[1].clone() - )); - - submit_and_check_execution_headers( - pallet_eth2_light_client::mock::RuntimeOrigin::signed(ALICE), - GOERLI_CHAIN, - headers[0].iter().skip(1).rev().collect(), - ); - - let mut header = headers[0][1].clone(); - let block_hash = pallet_eth2_light_client::FinalizedExecutionBlocks::::get( - GOERLI_CHAIN, - header.number, - ); - header.hash = block_hash; - - // setup light client payload - let light_proposal = LightProposalInput { - block_header: header, - merkle_root: [0; 32], - merkle_root_proof: vec![vec![0; 32]], - leaf_index: 0, - leaf_index_proof: vec![vec![0; 32]], - resource_id: *GOERLI_RESOURCE_ID, - }; - - assert_ok!(LightProposals::submit_proposal(RuntimeOrigin::signed(ALICE), light_proposal)); - }); -} - -#[test] -fn test_light_light_should_reject_if_header_is_not_present() { - new_test_ext().execute_with(|| { - // setup bridge registry with defaults - setup_bridge_registry(); - - let (headers, _updates, _init_input) = get_test_context(None); - - // setup light client payload - let light_proposal = LightProposalInput { - block_header: headers[0][1].clone(), - merkle_root: [0; 32], - merkle_root_proof: vec![vec![0; 32]], - leaf_index: 0, - leaf_index_proof: vec![vec![0; 32]], - resource_id: *GOERLI_RESOURCE_ID, - }; - - assert_err!( - LightProposals::submit_proposal(RuntimeOrigin::signed(ALICE), light_proposal), - pallet_eth2_light_client::Error::::HeaderHashDoesNotExist - ); - }); -} - -#[test] -fn test_light_light_should_reject_if_proof_verification_fails() { - new_test_ext().execute_with(|| { - // setup bridge registry with defaults - setup_bridge_registry(); - - // prep light client pallet - let (headers, updates, _init_input) = get_test_context(None); - assert_ok!(Eth2Client::submit_beacon_chain_light_client_update( - RuntimeOrigin::signed(ALICE), - GOERLI_CHAIN, - updates[1].clone() - )); - - submit_and_check_execution_headers( - pallet_eth2_light_client::mock::RuntimeOrigin::signed(ALICE), - GOERLI_CHAIN, - headers[0].iter().skip(1).rev().collect(), - ); - - let mut header = headers[0][1].clone(); - let block_hash = pallet_eth2_light_client::FinalizedExecutionBlocks::::get( - GOERLI_CHAIN, - header.number, - ); - header.hash = block_hash; - - // setup light client payload - let light_proposal = LightProposalInput { - block_header: header, - merkle_root: [0; 32], - merkle_root_proof: vec![vec![123]], - leaf_index: 0, - leaf_index_proof: vec![vec![0; 32]], - resource_id: *GOERLI_RESOURCE_ID, - }; - - assert_err!( - LightProposals::submit_proposal(RuntimeOrigin::signed(ALICE), light_proposal), - Error::::ProofVerificationFailed - ); - }); -} diff --git a/pallets/light-verifier/Cargo.toml b/pallets/light-verifier/Cargo.toml index f90a811e..e4973cd7 100644 --- a/pallets/light-verifier/Cargo.toml +++ b/pallets/light-verifier/Cargo.toml @@ -38,7 +38,6 @@ tiny-keccak = { workspace = true } bitvec = { workspace = true, features = ["atomic", "alloc"] } hex = { workspace = true } webb-light-client-primitives = { workspace = true } -dkg-runtime-primitives = { git = "https://github.com/webb-tools/dkg-substrate.git", branch = "master", default-features = false } [dev-dependencies] anyhow = { workspace = true } @@ -68,7 +67,6 @@ std = [ "sp-std/std", "sp-core/std", "hex/std", - "dkg-runtime-primitives/std", "pallet-eth2-light-client/std", # Local dependencies diff --git a/pallets/light-verifier/src/verify.rs b/pallets/light-verifier/src/verify.rs index fa665c6d..dfce4b35 100644 --- a/pallets/light-verifier/src/verify.rs +++ b/pallets/light-verifier/src/verify.rs @@ -1,7 +1,7 @@ use super::*; -use dkg_runtime_primitives::H256; use frame_support::ensure; use rlp::Rlp; +use sp_core::H256; /// A utility for working with trie proofs. pub struct TrieProver; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 699de8c6..238a9844 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2023-07-16" +channel = "nightly-2024-02-09" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] \ No newline at end of file From 3bd9e3237803e2bdaea2805accd9f0351183f9a6 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Mon, 26 Feb 2024 14:56:52 -0500 Subject: [PATCH 02/20] Update rust toolchain --- rust-toolchain.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 238a9844..5fe1a593 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-02-09" +channel = "nightly" components = ["rustfmt", "clippy"] -targets = ["wasm32-unknown-unknown"] \ No newline at end of file +targets = ["wasm32-unknown-unknown"] From 21b3a4c95107b6f2b51fc64eaf32b3478a4a4d0f Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Mon, 26 Feb 2024 15:17:34 -0500 Subject: [PATCH 03/20] Update dep --- Cargo.toml | 2 +- node/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5dcc69d..008b80f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ anyhow = "1.0" typed-builder = "0.16.0" log = { version = "0.4", default-features = false } serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } -serde = { version = "1.0", features = ["derive"], default-features = false } +serde = { version = "1.0.197", features = ["derive"], default-features = false } reqwest = { version = "0.11", features = ["blocking", "json"] } clap = { version = "4.0.9", features = ["derive"] } tokio = { version = "1.1", features = ["macros", "rt", "time", "signal"] } diff --git a/node/Cargo.toml b/node/Cargo.toml index e59586a5..60f1d55d 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -43,7 +43,7 @@ sp-io = { workspace = true } sp-timestamp = { workspace = true } sp-inherents = { workspace = true } sp-keyring = { workspace = true } -frame-system = { workspace = true } +frame-system = { workspace = true, features = ["std"] } pallet-staking = { workspace = true } pallet-transaction-payment = { workspace = true } From 39f1230e0b3cfefe6a941917b32892d23cd3cdbc Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Mon, 26 Feb 2024 15:27:23 -0500 Subject: [PATCH 04/20] Upds --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 008b80f9..4b5194cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,8 +84,8 @@ webb = { version = "0.7.3", default-features = false, features = [ webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } -types = { git = "https://github.com/webb-tools/lighthouse.git", rev="ef72e752eaf45f4b7eb64dd8dbb0fe088f955df8" } -merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git", rev="ef72e752eaf45f4b7eb64dd8dbb0fe088f955df8" } +types = { git = "https://github.com/sigp/lighthouse.git" } +merkle_proof = { git = "https://github.com/sigp/lighthouse.git" } tree_hash = { version = "0.5.0", features = ["arbitrary"], default-features = false } ethereum_hashing = { version = "1.0.0-beta.2", default-features = false } ethereum_ssz = { version = "0.5.0", features = ["arbitrary"], default-features = false } From 018a4e16aa0cca5c75e40ebe17f0caf129668874 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Mon, 26 Feb 2024 15:52:10 -0500 Subject: [PATCH 05/20] Fix --- node/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Cargo.toml b/node/Cargo.toml index 60f1d55d..e59586a5 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -43,7 +43,7 @@ sp-io = { workspace = true } sp-timestamp = { workspace = true } sp-inherents = { workspace = true } sp-keyring = { workspace = true } -frame-system = { workspace = true, features = ["std"] } +frame-system = { workspace = true } pallet-staking = { workspace = true } pallet-transaction-payment = { workspace = true } From c1b7b52ccbea78e505b953ab2b2707b1093106e8 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 12:01:59 -0500 Subject: [PATCH 06/20] Add serde feature --- Cargo.toml | 2 +- pallets/eth2-light-client/src/test_utils.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b5194cc..2aee1f59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,7 +107,7 @@ sc-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "r sc-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-consensus-grandpa = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sc-client-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0", features = ["serde"] } sp-io = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-inherents = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } diff --git a/pallets/eth2-light-client/src/test_utils.rs b/pallets/eth2-light-client/src/test_utils.rs index ea478071..b641a68a 100644 --- a/pallets/eth2-light-client/src/test_utils.rs +++ b/pallets/eth2-light-client/src/test_utils.rs @@ -1,5 +1,3 @@ -use eth_types::eth2::LightClientUpdate; - use eth_types::{eth2::*, pallet::InitInput, BlockHeader}; use lazy_static::lazy_static; From 24631248dcaebbec0cd803c1545dcb38ffe5acbd Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 12:15:37 -0500 Subject: [PATCH 07/20] Dep update --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2aee1f59..cf2a2f1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,7 @@ sc-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", bran sc-transaction-pool-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sc-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-consensus-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } -sp-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-consensus = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sc-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sc-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-consensus-grandpa = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } @@ -144,7 +144,7 @@ jsonrpsee = { version = "0.16.2", default-features = false } sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0", default-features = false } sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } -sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } +sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0", default-features = false } sc-basic-authorship = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } substrate-frame-rpc-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } From f100dcc281ebc6eebfc55e4c2a9c8cace981729b Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 13:55:35 -0500 Subject: [PATCH 08/20] Dep update --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cf2a2f1b..d8472458 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,8 +84,8 @@ webb = { version = "0.7.3", default-features = false, features = [ webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } -types = { git = "https://github.com/sigp/lighthouse.git" } -merkle_proof = { git = "https://github.com/sigp/lighthouse.git" } +types = { git = "https://github.com/webb-tools/lighthouse.git", branch = "salman/update-sqlite-deps" } +merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git", branch = "salman/update-sqlite-deps" } tree_hash = { version = "0.5.0", features = ["arbitrary"], default-features = false } ethereum_hashing = { version = "1.0.0-beta.2", default-features = false } ethereum_ssz = { version = "0.5.0", features = ["arbitrary"], default-features = false } From 153d714205627a33bfa79a2bb2cdfd46e4665fad Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 14:03:43 -0500 Subject: [PATCH 09/20] Fix --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d8472458..e822b5de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,15 +77,15 @@ zeroize = { version = "1.4.2", features = [ ], default-features = false } subxt = "0.29.0" -webb = { version = "0.7.3", default-features = false, features = [ +webb = { version = "0.8.4", default-features = false, features = [ "evm-runtime", "substrate-runtime", ]} webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } -types = { git = "https://github.com/webb-tools/lighthouse.git", branch = "salman/update-sqlite-deps" } -merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git", branch = "salman/update-sqlite-deps" } +types = { git = "https://github.com/webb-tools/lighthouse.git" } +merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git" } tree_hash = { version = "0.5.0", features = ["arbitrary"], default-features = false } ethereum_hashing = { version = "1.0.0-beta.2", default-features = false } ethereum_ssz = { version = "0.5.0", features = ["arbitrary"], default-features = false } From 8d27ec51f2425d8512a4a7f442640354331a34ec Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 15:34:57 -0500 Subject: [PATCH 10/20] Fix deps --- node/Cargo.toml | 2 +- runtime/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Cargo.toml b/node/Cargo.toml index e59586a5..fe79c3b8 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -72,7 +72,7 @@ frame-benchmarking-cli = { workspace = true } try-runtime-cli = { workspace = true, optional = true } [build-dependencies] -substrate-build-script-utils = { version = "3.0.0", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +substrate-build-script-utils = { version = "11.0.0", git = "https://github.com/paritytech/polkadot-sdk" } [features] default = [] diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 787a632f..0a2c1d8e 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -63,7 +63,7 @@ pallet-eth2-light-client = { path = "../pallets/eth2-light-client", default-feat pallet-eth2-light-client-runtime-api = { path = "../pallets/eth2-light-client/runtime-api", default-features = false } [build-dependencies] -substrate-wasm-builder = { version = "5.0.0-dev", git = "https://github.com/paritytech/polkadot-sdk", optional = true , branch = "release-polkadot-v1.1.0" } +substrate-wasm-builder = { version = "17.0.0", git = "https://github.com/paritytech/polkadot-sdk", optional = true , branch = "release-polkadot-v1.7.0" } [features] default = ["std"] From 5cc789e354c029286d22ced12b26744d74b4e70d Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 28 Feb 2024 16:38:01 -0500 Subject: [PATCH 11/20] Get building --- Cargo.toml | 6 +++--- node/src/chain_spec.rs | 3 ++- node/src/rpc.rs | 9 ++++++++- node/src/service.rs | 8 +++++--- runtime/src/lib.rs | 37 +++++++++++++++++++++++++------------ 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e822b5de..1f472447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,12 +77,12 @@ zeroize = { version = "1.4.2", features = [ ], default-features = false } subxt = "0.29.0" -webb = { version = "0.8.4", default-features = false, features = [ +webb = { version = "0.7.3", default-features = false, features = [ "evm-runtime", "substrate-runtime", ]} -webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"] } +webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"], branch = "polkadot-v1.7.0" } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } types = { git = "https://github.com/webb-tools/lighthouse.git" } merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git" } @@ -140,7 +140,7 @@ frame-election-provider-support = { default-features = false, git = "https://git pallet-election-provider-multi-phase = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.16.2", default-features = false } +jsonrpsee = { version = "0.20.3", features = ["server"] } sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } sp-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0", default-features = false } sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.7.0" } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index bc95ca80..7dea8d58 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -76,6 +76,7 @@ pub fn development_config() -> ChainSpec { None, None, Default::default(), + WASM_BINARY.unwrap(), ) } @@ -103,6 +104,7 @@ pub fn local_testnet_config() -> ChainSpec { None, None, Default::default(), + WASM_BINARY.unwrap(), ) } @@ -164,7 +166,6 @@ fn testnet_genesis( RuntimeGenesisConfig { system: SystemConfig { // Add Wasm runtime to storage. - code: wasm_binary.to_vec(), ..Default::default() }, balances: BalancesConfig { diff --git a/node/src/rpc.rs b/node/src/rpc.rs index 53c59bc0..246391ad 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -45,7 +45,7 @@ where let mut module = RpcModule::new(()); let FullDeps { client, pool, deny_unsafe } = deps; - module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; module.merge(TransactionPayment::new(client).into_rpc())?; // Extend this RPC with a custom API by using the following syntax. @@ -53,5 +53,12 @@ where // to call into the runtime. // `module.merge(YourRpcTrait::into_rpc(YourRpcStruct::new(ReferenceToClient, ...)))?;` + // You probably want to enable the `rpc v2 chainSpec` API as well + // + // let chain_name = chain_spec.name().to_string(); + // let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + // let properties = chain_spec.properties(); + // module.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?; + Ok(module) } diff --git a/node/src/service.rs b/node/src/service.rs index b58c90ad..1fd63253 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -166,9 +166,9 @@ pub fn new_full( &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); - net_config.add_notification_protocol(sc_consensus_grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); + let (grandpa_protocol_config, grandpa_notification_service) = + sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( backend.clone(), @@ -186,6 +186,7 @@ pub fn new_full( import_queue, block_announce_validator_builder: None, warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + block_relay: None, })?; let role = config.role.clone(); @@ -335,6 +336,7 @@ pub fn new_full( shared_voter_state: SharedVoterState::empty(), telemetry: telemetry.as_ref().map(|x| x.handle()), offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool), + notification_service: grandpa_notification_service, }; // the GRANDPA voter task is considered infallible, i.e. diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index de15a363..945a4f13 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -16,7 +16,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use pallet_election_provider_multi_phase::SolutionAccuracyOf; +use pallet_election_provider_multi_phase::{BalanceOf, GeometricDepositBase, SolutionAccuracyOf}; use pallet_eth2_light_client_runtime_api::runtime_decl_for_eth_2_light_client_api::{ ClientMode, LightClientState, TypedChainId, }; @@ -27,15 +27,14 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, curve::PiecewiseLinear, - generic, - generic::Era, + generic::{self, Era}, impl_opaque_keys, traits::{ - self, BlakeTwo256, Block as BlockT, Get, IdentifyAccount, NumberFor, One, OpaqueKeys, - SaturatedConversion, StaticLookup, Verify, + self, BlakeTwo256, Block as BlockT, Convert, Get, IdentifyAccount, NumberFor, One, + OpaqueKeys, SaturatedConversion, StaticLookup, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, MultiSignature, Percent, }; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -230,6 +229,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; /// The set code logic, just the default since we're not a parachain. type OnSetCode = (); + type RuntimeTask = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -302,7 +302,6 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -310,6 +309,8 @@ impl pallet_staking::Config for Runtime { // This a placeholder, to be introduced in the next PR as an instance of bags-list type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<5900>; + type MaxExposurePageSize = ConstU32<32>; type HistoryDepth = HistoryDepth; type NominationsQuota = pallet_staking::FixedNominationsQuota; type EventListeners = (); @@ -329,8 +330,6 @@ parameter_types! { pub const SignedDepositBase: Balance = DOLLARS; pub const SignedDepositByte: Balance = CENTS; - pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(1u32, 10_000); - // miner configs pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; pub MinerMaxWeight: Weight = RuntimeBlockWeights::get() @@ -370,6 +369,9 @@ parameter_types! { .voters_count(10_000.into()).targets_count(1_500.into()).build(); pub ElectionBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default() .voters_count(5_000.into()).targets_count(1_250.into()).build(); + pub EnableVariableDepositBase: bool = false; + pub SignedFixedDeposit: Balance = 5; + pub SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); } /// The numbers configured here could always be more than the the maximum limits of staking pallet @@ -450,14 +452,13 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type EstimateCallFee = TransactionPayment; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; - type BetterUnsignedThreshold = BetterUnsignedThreshold; type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; type MinerTxPriority = MultiPhaseUnsignedPriority; type MinerConfig = Self; type SignedMaxSubmissions = ConstU32<10>; type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = SignedDepositBase; + type SignedDepositBase = Self; type SignedDepositByte = SignedDepositByte; type SignedMaxRefunds = ConstU32<3>; type SignedDepositWeight = (); @@ -475,6 +476,18 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; } +impl Convert> for Runtime { + /// returns the geometric increase deposit fee if `EnableVariableDepositBase` is set, otherwise + /// the fee is `SignedFixedDeposit`. + fn convert(queue_len: usize) -> Balance { + if !EnableVariableDepositBase::get() { + SignedFixedDeposit::get() + } else { + GeometricDepositBase::::convert(queue_len) + } + } +} + parameter_types! { pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS; } @@ -546,7 +559,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxFreezes = (); type RuntimeHoldReason = RuntimeHoldReason; - type MaxHolds = (); + type RuntimeFreezeReason = (); } parameter_types! { From 36308467dd6e3049e4b4d0f9b0eb9c99e4adc42b Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 22:26:22 +0530 Subject: [PATCH 12/20] use tangle subxt and use polkadot-v1.70 --- Cargo.toml | 14 ++++---- crates/consensus-types/Cargo.toml | 2 +- crates/eth-types/Cargo.toml | 2 +- crates/eth2-pallet-init/Cargo.toml | 9 +++-- .../metadata/tangle-runtime.scale | Bin 178465 -> 0 bytes .../src/eth_client_pallet_trait.rs | 2 +- crates/eth2-pallet-init/src/init_pallet.rs | 2 +- crates/eth2-pallet-init/src/lib.rs | 2 +- crates/eth2-pallet-init/src/misc.rs | 2 +- .../src/substrate_pallet_client.rs | 31 ++++++++---------- crates/lc-relay-types/Cargo.toml | 2 +- eth2substrate-block-relay-rs/Cargo.toml | 6 ++-- node/src/chain_spec.rs | 7 ++-- node/src/service.rs | 1 + pallets/eth2-light-client/Cargo.toml | 2 +- .../eth2-light-client/runtime-api/Cargo.toml | 2 +- pallets/light-verifier/Cargo.toml | 3 +- primitives/Cargo.toml | 3 +- runtime/Cargo.toml | 3 +- runtime/src/lib.rs | 8 +++-- rust-toolchain.toml | 2 +- 21 files changed, 52 insertions(+), 53 deletions(-) delete mode 100644 crates/eth2-pallet-init/metadata/tangle-runtime.scale diff --git a/Cargo.toml b/Cargo.toml index 1f472447..b2b36837 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "runtime", "primitives", ] +resolver = "2" [patch] [patch.crates-io] @@ -31,7 +32,7 @@ typed-builder = "0.16.0" log = { version = "0.4", default-features = false } serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } serde = { version = "1.0.197", features = ["derive"], default-features = false } -reqwest = { version = "0.11", features = ["blocking", "json"] } +reqwest = { version = "0.11.22", features = ["blocking", "json"] } clap = { version = "4.0.9", features = ["derive"] } tokio = { version = "1.1", features = ["macros", "rt", "time", "signal"] } env_logger = "0.9.0" @@ -76,13 +77,10 @@ zeroize = { version = "1.4.2", features = [ "zeroize_derive", ], default-features = false } -subxt = "0.29.0" -webb = { version = "0.7.3", default-features = false, features = [ - "evm-runtime", - "substrate-runtime", -]} - -webb-proposals = { git = "https://github.com/webb-tools/webb-rs", default-features = false, features = ["scale", "evm"], branch = "polkadot-v1.7.0" } +subxt = "0.31.0" +subxt-signer = "0.31.0" +tangle-subxt = { git = "https://github.com/webb-tools/tangle" , rev = "8be20aa02a764422e1fd0ba30bc70b99d5f66887"} +webb-proposals = { git = "https://github.com/webb-tools/webb-rs", branch = "salman/polkadot-v1.7.0", default-features = false, features = ["scale", "evm"] } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", default-features = false, rev="a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" } types = { git = "https://github.com/webb-tools/lighthouse.git" } merkle_proof = { git = "https://github.com/webb-tools/lighthouse.git" } diff --git a/crates/consensus-types/Cargo.toml b/crates/consensus-types/Cargo.toml index 671ebe1d..ed5cbb98 100644 --- a/crates/consensus-types/Cargo.toml +++ b/crates/consensus-types/Cargo.toml @@ -16,7 +16,7 @@ eth2-serde-utils = { package = "webb-eth2-serde-utils", path = "../serde-utils", bitvec = { workspace = true, features = ["atomic", "alloc"] } hex = { workspace = true } -codec = { workspace = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { workspace = true } serde = { workspace = true } rlp = { workspace = true } diff --git a/crates/eth-types/Cargo.toml b/crates/eth-types/Cargo.toml index 2981ac99..f5baff2d 100644 --- a/crates/eth-types/Cargo.toml +++ b/crates/eth-types/Cargo.toml @@ -12,7 +12,7 @@ tree-hash = { package = "webb-tree-hash", path = "../tree-hash", default-featur tree-hash-derive = { package = "webb-tree-hash-derive", path = "../tree-hash-derive", default-features = false } eth2-serde-utils = { package = "webb-eth2-serde-utils", path = "../serde-utils", default-features = false, optional = true } hex = { workspace = true } -codec = { workspace = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } scale-info = { workspace = true } serde = { workspace = true } rlp = { workspace = true } diff --git a/crates/eth2-pallet-init/Cargo.toml b/crates/eth2-pallet-init/Cargo.toml index a5eb6c88..2a46bda7 100644 --- a/crates/eth2-pallet-init/Cargo.toml +++ b/crates/eth2-pallet-init/Cargo.toml @@ -21,9 +21,12 @@ serde_json = { workspace = true } serde = { workspace = true } toml = { workspace = true } async-trait = { workspace = true } -sp-keyring = { version = "24.0.0", default-features = false } -subxt = { workspace = true } -webb = { workspace = true } +sp-keyring = { workspace = true } +sp-core = { workspace = true } +subxt = { workspace = true, features = ["substrate-compat"] } +codec = { workspace = true } +subxt-signer = { workspace = true } +tangle-subxt = { workspace = true } scale-info = { workspace = true } webb-proposals = { workspace = true, features = ["scale", "evm"] } tokio = { workspace = true, features = ["macros", "rt", "time"] } diff --git a/crates/eth2-pallet-init/metadata/tangle-runtime.scale b/crates/eth2-pallet-init/metadata/tangle-runtime.scale deleted file mode 100644 index af2ae0b36ff965daaf427f233d1b73afd3649191..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178465 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 RL5=KPsyMgj_1>HJe*rdsEV=*y diff --git a/crates/eth2-pallet-init/src/eth_client_pallet_trait.rs b/crates/eth2-pallet-init/src/eth_client_pallet_trait.rs index 82d8dfb4..c9971939 100644 --- a/crates/eth2-pallet-init/src/eth_client_pallet_trait.rs +++ b/crates/eth2-pallet-init/src/eth_client_pallet_trait.rs @@ -6,7 +6,7 @@ use eth_types::{ BlockHeader, H256, }; -use webb::substrate::subxt::utils::AccountId32; +use tangle_subxt::subxt::utils::AccountId32; pub type Balance = u128; diff --git a/crates/eth2-pallet-init/src/init_pallet.rs b/crates/eth2-pallet-init/src/init_pallet.rs index 511f8cdf..94a2fc1a 100644 --- a/crates/eth2-pallet-init/src/init_pallet.rs +++ b/crates/eth2-pallet-init/src/init_pallet.rs @@ -5,9 +5,9 @@ use eth_rpc_client::{ }; use eth_types::{eth2::ExtendedBeaconBlockHeader, BlockHeader}; use log::info; +use tangle_subxt::subxt::utils::AccountId32; use tree_hash::TreeHash; use types::{ExecutionPayload, MainnetEthSpec}; -use webb::substrate::subxt::utils::AccountId32; use webb_proposals::TypedChainId; const CURRENT_SYNC_COMMITTEE_INDEX: u32 = 54; const CURRENT_SYNC_COMMITTEE_TREE_DEPTH: u32 = diff --git a/crates/eth2-pallet-init/src/lib.rs b/crates/eth2-pallet-init/src/lib.rs index 56df2ea8..cdb5d86a 100644 --- a/crates/eth2-pallet-init/src/lib.rs +++ b/crates/eth2-pallet-init/src/lib.rs @@ -8,4 +8,4 @@ pub mod init_pallet; pub mod misc; pub mod substrate_network; pub mod substrate_pallet_client; -pub use webb::substrate::tangle_runtime::api as tangle; +pub use tangle_subxt::tangle_runtime::api as tangle; diff --git a/crates/eth2-pallet-init/src/misc.rs b/crates/eth2-pallet-init/src/misc.rs index e0bac91a..f68ad071 100644 --- a/crates/eth2-pallet-init/src/misc.rs +++ b/crates/eth2-pallet-init/src/misc.rs @@ -1,4 +1,4 @@ -use webb::substrate::{scale::Encode, subxt::dynamic::Value}; +use tangle_subxt::{parity_scale_codec::Encode, subxt::dynamic::Value}; pub trait AsValue: Encode { fn as_value(&self) -> Value; diff --git a/crates/eth2-pallet-init/src/substrate_pallet_client.rs b/crates/eth2-pallet-init/src/substrate_pallet_client.rs index 062545c4..b4b8073b 100644 --- a/crates/eth2-pallet-init/src/substrate_pallet_client.rs +++ b/crates/eth2-pallet-init/src/substrate_pallet_client.rs @@ -8,21 +8,20 @@ use eth_types::{ BlockHeader, H256, }; +use codec::{Decode, Encode}; use std::sync::Arc; -use subxt::{error::DispatchError, utils::AccountId32}; -use webb::substrate::{ - scale::{Decode, Encode}, - subxt::{ - self, - ext::sp_core::{sr25519::Pair, Pair as _}, - storage::{address::Yes, StorageAddress}, - tx::{PairSigner, TxPayload, TxStatus}, - OnlineClient, PolkadotConfig, - }, +use subxt::{ + self, + error::DispatchError, + ext::sp_core::{sr25519::Pair, Pair as _}, + storage::{address::Yes, StorageAddress}, + tx::{PairSigner, TxPayload, TxStatus}, + utils::AccountId32, + OnlineClient, PolkadotConfig, }; -use webb_proposals::TypedChainId; -use tangle::runtime_types::pallet_eth2_light_client; +use tangle_subxt::tangle_runtime::{api as tangle, api::runtime_types::pallet_eth2_light_client}; +use webb_proposals::TypedChainId; pub fn convert_typed_chain_ids( t: TypedChainId, @@ -72,7 +71,7 @@ pub struct EthClientPallet { impl EthClientPallet { pub fn new(api: Arc>, typed_chain_id: TypedChainId) -> Self { - Self::new_with_pair(api, sp_keyring::AccountKeyring::Alice.pair(), typed_chain_id) + Self::new_with_pair(api, Pair::from_string("//Alice", None).unwrap(), typed_chain_id) } pub fn new_with_pair( @@ -321,8 +320,7 @@ impl EthClientPalletTrait for EthClientPallet { typed_chain_id: decoded_tcid, block_header: decoded_header, }; - let tx = - tangle::runtime_types::tangle_standalone_runtime::RuntimeCall::Eth2Client(call); + let tx = tangle::runtime_types::tangle_testnet_runtime::RuntimeCall::Eth2Client(call); txes.push(tx); } @@ -441,6 +439,3 @@ fn get_sr25519_keys_from_suri>(suri: T) -> anyhow::Result { } } } - -#[subxt::subxt(runtime_metadata_path = "./metadata/tangle-runtime.scale")] -pub mod tangle {} diff --git a/crates/lc-relay-types/Cargo.toml b/crates/lc-relay-types/Cargo.toml index 4cf5429c..8bb1bfbe 100644 --- a/crates/lc-relay-types/Cargo.toml +++ b/crates/lc-relay-types/Cargo.toml @@ -10,7 +10,7 @@ serde = { workspace = true } serde_json = { workspace = true } reqwest = { workspace = true, features = ["blocking", "json"] } anyhow = { workspace = true } -webb = { workspace = true} +tangle-subxt = { workspace = true} tracing = { workspace = true } backoff = { workspace = true } tokio = { workspace = true } diff --git a/eth2substrate-block-relay-rs/Cargo.toml b/eth2substrate-block-relay-rs/Cargo.toml index 72726dc7..1d4bcea8 100644 --- a/eth2substrate-block-relay-rs/Cargo.toml +++ b/eth2substrate-block-relay-rs/Cargo.toml @@ -19,12 +19,12 @@ lc-relayer-context = { package = "webb-lc-relayer-context", path = "../crates/lc types = { workspace = true } eth2_hashing = { package = "ethereum_hashing", version = "1.0.0-beta.2" } eth2_ssz = { package = "ethereum_ssz", version = "0.5.0", features = ["arbitrary"] } -webb = { workspace = true } +tangle-subxt = { workspace = true } webb-proposals ={ workspace = true } anyhow = { workspace = true } funty = { workspace = true } -sp-keyring = { version = "18.0.0", default-features = false } -sp-core = { version = "16.0.0" } +sp-keyring = { workspace = true } +sp-core = { workspace = true } log = { workspace = true, features = ["std", "serde"] } serde_json = { workspace = true } serde = { workspace = true } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 7dea8d58..2cbcbe56 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -53,9 +53,7 @@ fn session_keys(grandpa: GrandpaId, aura: AuraId) -> SessionKeys { } fn development_config_genesis() -> RuntimeGenesisConfig { - let wasm_binary = WASM_BINARY.unwrap(); testnet_genesis( - wasm_binary, vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], vec![], get_account_id_from_seed::("Alice"), @@ -65,6 +63,7 @@ fn development_config_genesis() -> RuntimeGenesisConfig { /// Development config (single validator Alice) pub fn development_config() -> ChainSpec { + let wasm_binary = WASM_BINARY.unwrap(); ChainSpec::from_genesis( "Development", "dev", @@ -81,9 +80,7 @@ pub fn development_config() -> ChainSpec { } fn local_testnet_genesis() -> RuntimeGenesisConfig { - let wasm_binary = WASM_BINARY.unwrap(); testnet_genesis( - wasm_binary, vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], vec![], get_account_id_from_seed::("Alice"), @@ -93,6 +90,7 @@ fn local_testnet_genesis() -> RuntimeGenesisConfig { /// Local testnet config (multivalidator Alice + Bob) pub fn local_testnet_config() -> ChainSpec { + let wasm_binary = WASM_BINARY.unwrap(); ChainSpec::from_genesis( "Local Testnet", "local_testnet", @@ -110,7 +108,6 @@ pub fn local_testnet_config() -> ChainSpec { /// Configure initial storage state for FRAME modules. fn testnet_genesis( - wasm_binary: &[u8], initial_authorities: Vec<(AccountId, AccountId, GrandpaId, AuraId)>, initial_nominators: Vec, root_key: AccountId, diff --git a/node/src/service.rs b/node/src/service.rs index 1fd63253..014f67d9 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -331,6 +331,7 @@ pub fn new_full( link: grandpa_link, network, sync: Arc::new(sync_service), + notification_service: grandpa_notification_service, voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), diff --git a/pallets/eth2-light-client/Cargo.toml b/pallets/eth2-light-client/Cargo.toml index 3c5c685c..f0a45bc1 100644 --- a/pallets/eth2-light-client/Cargo.toml +++ b/pallets/eth2-light-client/Cargo.toml @@ -25,7 +25,7 @@ sp-core = { workspace = true } log = { workspace = true } serde = { workspace = true, optional = true } -codec = { workspace = true, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { workspace = true } webb-proposals = { workspace = true, features = ["evm", "substrate"] } ethereum-types = { workspace = true } diff --git a/pallets/eth2-light-client/runtime-api/Cargo.toml b/pallets/eth2-light-client/runtime-api/Cargo.toml index 89809a65..868ff1c5 100644 --- a/pallets/eth2-light-client/runtime-api/Cargo.toml +++ b/pallets/eth2-light-client/runtime-api/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { workspace = true } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } sp-api = { workspace = true } webb-proposals = { workspace = true } eth-types = { path = "../../../crates/eth-types", default-features = false } diff --git a/pallets/light-verifier/Cargo.toml b/pallets/light-verifier/Cargo.toml index e4973cd7..32e7b611 100644 --- a/pallets/light-verifier/Cargo.toml +++ b/pallets/light-verifier/Cargo.toml @@ -26,7 +26,8 @@ sp-core = { workspace = true } log = { workspace = true } serde = { workspace = true, optional = true } -codec = { workspace = true, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } + scale-info = { workspace = true } webb-proposals = { workspace = true, features = ["evm", "substrate"] } ethereum-types = { workspace = true } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 9cae80c8..12890217 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -14,7 +14,8 @@ webb-proposals = { workspace = true } ethereum-types = { workspace = true } log = { workspace = true } serde = { workspace = true, optional = true } -codec = { workspace = true, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } + scale-info = { workspace = true } [features] diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 0a2c1d8e..91c25f78 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -13,7 +13,8 @@ repository = "https://github.com/substrate-developer-hub/substrate-node-template targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { workspace = true, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } + scale-info = { workspace = true } log = { workspace = true } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 945a4f13..5d331668 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -11,7 +11,7 @@ use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; -use frame_support::{dispatch::DispatchClass, PalletId}; +use frame_support::{derive_impl, dispatch::DispatchClass, PalletId}; use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, @@ -183,7 +183,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. - +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { /// The basic call filter to use in dispatchable. type BaseCallFilter = frame_support::traits::Everything; @@ -273,6 +273,7 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); + pub const MaxControllersInDeprecationBatch: u32 = 5900; pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; } @@ -327,7 +328,8 @@ parameter_types! { // signed config pub const SignedRewardBase: Balance = DOLLARS; - pub const SignedDepositBase: Balance = DOLLARS; + pub const SignedFixedDeposit: Balance = 1 * DOLLARS; + pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); pub const SignedDepositByte: Balance = CENTS; // miner configs diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5fe1a593..28649a27 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly" +channel = "nightly-2024-01-31" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From 7604745c9350161df240e732b8ae9c260c695a96 Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 22:36:05 +0530 Subject: [PATCH 13/20] post merge fixes --- node/src/chain_spec.rs | 2 -- node/src/service.rs | 1 - runtime/src/lib.rs | 2 -- 3 files changed, 5 deletions(-) diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 2cbcbe56..fea41e7f 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -63,7 +63,6 @@ fn development_config_genesis() -> RuntimeGenesisConfig { /// Development config (single validator Alice) pub fn development_config() -> ChainSpec { - let wasm_binary = WASM_BINARY.unwrap(); ChainSpec::from_genesis( "Development", "dev", @@ -90,7 +89,6 @@ fn local_testnet_genesis() -> RuntimeGenesisConfig { /// Local testnet config (multivalidator Alice + Bob) pub fn local_testnet_config() -> ChainSpec { - let wasm_binary = WASM_BINARY.unwrap(); ChainSpec::from_genesis( "Local Testnet", "local_testnet", diff --git a/node/src/service.rs b/node/src/service.rs index 014f67d9..67f685ec 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -337,7 +337,6 @@ pub fn new_full( shared_voter_state: SharedVoterState::empty(), telemetry: telemetry.as_ref().map(|x| x.handle()), offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool), - notification_service: grandpa_notification_service, }; // the GRANDPA voter task is considered infallible, i.e. diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 5d331668..7c2dc37f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -328,8 +328,6 @@ parameter_types! { // signed config pub const SignedRewardBase: Balance = DOLLARS; - pub const SignedFixedDeposit: Balance = 1 * DOLLARS; - pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); pub const SignedDepositByte: Balance = CENTS; // miner configs From 23329f1a7063ee9f38403081d2b012acccfee7db Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 22:44:21 +0530 Subject: [PATCH 14/20] update mock config and toochain --- pallets/light-verifier/src/mock.rs | 3 ++- rust-toolchain.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pallets/light-verifier/src/mock.rs b/pallets/light-verifier/src/mock.rs index 56843bed..5f7391ec 100644 --- a/pallets/light-verifier/src/mock.rs +++ b/pallets/light-verifier/src/mock.rs @@ -46,6 +46,7 @@ impl system::Config for Test { type DbWeight = (); type RuntimeEvent = RuntimeEvent; type Hash = H256; + type RuntimeTask = (); type Hashing = BlakeTwo256; type Lookup = IdentityLookup; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -73,7 +74,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type FreezeIdentifier = (); - type MaxHolds = (); + type RuntimeFreezeReason = (); type MaxFreezes = (); type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 28649a27..5fe1a593 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-01-31" +channel = "nightly" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From 2a759b37e0b607c4c4480d406ce8c68ab6b39682 Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 22:46:37 +0530 Subject: [PATCH 15/20] update CI job --- .github/workflows/validate_pr.yml | 4 ++-- rust-toolchain.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml index 7013aedf..3a79a875 100644 --- a/.github/workflows/validate_pr.yml +++ b/.github/workflows/validate_pr.yml @@ -16,7 +16,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2023-07-16 + toolchain: nightly-2024-01-31 components: clippy override: true @@ -25,7 +25,7 @@ jobs: uses: actions-rs/toolchain@master with: profile: minimal - toolchain: nightly-2023-07-16 + toolchain: nightly-2024-01-31 target: wasm32-unknown-unknown - name: Install protobuf-compiler diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5fe1a593..28649a27 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly" +channel = "nightly-2024-01-31" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From e5f46d7f296f99450fe1eef51742e18c81ce9d99 Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 22:51:10 +0530 Subject: [PATCH 16/20] use nightly latest --- .github/workflows/validate_pr.yml | 4 ++-- rust-toolchain.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml index 3a79a875..ea1bdc3b 100644 --- a/.github/workflows/validate_pr.yml +++ b/.github/workflows/validate_pr.yml @@ -16,7 +16,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2024-01-31 + toolchain: nightly components: clippy override: true @@ -25,7 +25,7 @@ jobs: uses: actions-rs/toolchain@master with: profile: minimal - toolchain: nightly-2024-01-31 + toolchain: nightly target: wasm32-unknown-unknown - name: Install protobuf-compiler diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 28649a27..5fe1a593 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-01-31" +channel = "nightly" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From 03a2d872c7e0cbda120d66e07080cd5ff363aa46 Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 23:10:56 +0530 Subject: [PATCH 17/20] fix clippy --- crates/eth2-hashing/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/eth2-hashing/src/lib.rs b/crates/eth2-hashing/src/lib.rs index f31e94d4..dc1c48c9 100644 --- a/crates/eth2-hashing/src/lib.rs +++ b/crates/eth2-hashing/src/lib.rs @@ -9,6 +9,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] +#[allow(unused_imports)] extern crate alloc; use alloc::{vec, vec::Vec}; From 1c5afa31351d32976111808d18bf0899bd9a75fc Mon Sep 17 00:00:00 2001 From: salman01zp Date: Fri, 1 Mar 2024 23:37:48 +0530 Subject: [PATCH 18/20] fix Clippy --- crates/eth2-hashing/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eth2-hashing/src/lib.rs b/crates/eth2-hashing/src/lib.rs index dc1c48c9..015d0a38 100644 --- a/crates/eth2-hashing/src/lib.rs +++ b/crates/eth2-hashing/src/lib.rs @@ -9,7 +9,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -#[allow(unused_imports)] +#![allow(unused_imports)] extern crate alloc; use alloc::{vec, vec::Vec}; From ce88dc8249af5abe11b9650f83fcb3d69953d991 Mon Sep 17 00:00:00 2001 From: salman01zp Date: Wed, 6 Mar 2024 14:11:15 +0530 Subject: [PATCH 19/20] use stable rust --- .github/workflows/validate_pr.yml | 54 ++++++++++++--- crates/bls/src/generic_aggregate_signature.rs | 4 +- crates/bls/src/impls/milagro.rs | 4 +- crates/bls/src/lib.rs | 10 +-- crates/bls/tests/tests.rs | 4 +- crates/consensus-types/src/lib.rs | 6 +- crates/consensus-types/src/network_config.rs | 4 +- .../eth-rpc-client/src/beacon_rpc_client.rs | 13 ++-- crates/eth-rpc-client/src/eth1_rpc_client.rs | 2 +- .../src/execution_block_proof.rs | 2 +- .../hand_made_finality_light_client_update.rs | 12 ++-- crates/eth-rpc-client/src/utils.rs | 4 +- crates/eth-types/src/lib.rs | 2 +- crates/eth2-pallet-init/src/init_pallet.rs | 14 ++-- .../src/substrate_pallet_client.rs | 58 ++++++++++------- crates/finality-update-verify/src/lib.rs | 4 +- crates/lc-relay-types/src/lib.rs | 8 +-- crates/lc-relayer-context/src/lib.rs | 2 +- crates/merkle-proof/src/lib.rs | 8 +-- crates/serde-utils/src/fixed_bytes_hex.rs | 2 +- crates/serde-utils/src/u256_hex_be.rs | 2 +- crates/serde-utils/src/u64_hex_be.rs | 4 +- crates/serde-utils/src/u8_hex.rs | 2 +- crates/ssz-derive/src/lib.rs | 9 +-- crates/ssz/examples/struct_definition.rs | 14 ++-- crates/ssz/src/decode.rs | 11 ++-- crates/ssz/src/decode/impls.rs | 6 +- crates/ssz/src/legacy.rs | 2 +- crates/tree-hash-derive/src/lib.rs | 9 +-- crates/tree-hash/src/lib.rs | 2 +- crates/tree-hash/src/merkle_hasher.rs | 10 +-- crates/tree-hash/src/merkleize_padded.rs | 2 +- crates/tree-hash/src/merkleize_standard.rs | 2 +- .../src/eth2substrate_relay.rs | 65 ++++++++++--------- .../src/test_utils.rs | 2 +- gadget/src/lib.rs | 13 ++-- node/src/chain_spec.rs | 2 + node/src/command.rs | 12 ++-- pallets/eth2-light-client/src/lib.rs | 27 ++++---- pallets/eth2-light-client/src/tests.rs | 14 ++-- pallets/light-verifier/src/lib.rs | 1 - runtime/src/lib.rs | 4 +- rust-toolchain.toml | 2 +- 43 files changed, 246 insertions(+), 188 deletions(-) diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml index ea1bdc3b..d03eab5e 100644 --- a/.github/workflows/validate_pr.yml +++ b/.github/workflows/validate_pr.yml @@ -8,24 +8,21 @@ on: jobs: test: + concurrency: + group: clippy-${{ github.ref }} + cancel-in-progress: true runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - components: clippy - override: true - name: Install toolchain id: toolchain uses: actions-rs/toolchain@master with: profile: minimal - toolchain: nightly + toolchain: stable target: wasm32-unknown-unknown - name: Install protobuf-compiler @@ -37,5 +34,44 @@ jobs: - name: Test workspace run: cargo test --package pallet-eth2-light-client - - name: Clippy - run: cargo clippy --package pallet-eth2-light-client -- -D warnings \ No newline at end of file + rustfmt: + concurrency: + group: rustfmt-${{ github.ref }} + cancel-in-progress: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install latest stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt + + - name: Rustfmt check + run: cargo fmt --all -- --check + + clippy: + concurrency: + group: clippy-${{ github.ref }} + cancel-in-progress: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install toolchain + id: toolchain + uses: actions-rs/toolchain@master + with: + profile: minimal + toolchain: stable + target: wasm32-unknown-unknown + + - name: Rust Cache + uses: Swatinem/rust-cache@v1.3.0 + + - name: Install Protobuf + run: sudo apt-get install protobuf-compiler + + - name: Run clippy + run: cargo clippy --package pallet-eth2-light-client -- -D warnings diff --git a/crates/bls/src/generic_aggregate_signature.rs b/crates/bls/src/generic_aggregate_signature.rs index 5d7f9f04..ce281341 100644 --- a/crates/bls/src/generic_aggregate_signature.rs +++ b/crates/bls/src/generic_aggregate_signature.rs @@ -196,7 +196,7 @@ where /// Verify that `self` represents an aggregate signature where all `pubkeys` have signed `msg`. pub fn fast_aggregate_verify(&self, msg: Hash256, pubkeys: &[&GenericPublicKey]) -> bool { if pubkeys.is_empty() { - return false + return false; } match self.point.as_ref() { @@ -227,7 +227,7 @@ where /// This function only exists for EF tests, it's presently not used in production. pub fn aggregate_verify(&self, msgs: &[Hash256], pubkeys: &[&GenericPublicKey]) -> bool { if msgs.is_empty() || msgs.len() != pubkeys.len() { - return false + return false; } match self.point.as_ref() { diff --git a/crates/bls/src/impls/milagro.rs b/crates/bls/src/impls/milagro.rs index 0e94d716..ad2bb108 100644 --- a/crates/bls/src/impls/milagro.rs +++ b/crates/bls/src/impls/milagro.rs @@ -32,7 +32,7 @@ pub fn verify_signature_sets<'a>( seed: [u8; 32], ) -> bool { if signature_sets.len() == 0 { - return false + return false; } signature_sets @@ -46,7 +46,7 @@ pub fn verify_signature_sets<'a>( } if signature_set.signature.point().is_none() { - return Err(()) + return Err(()); } Ok((signature_set.signature.as_ref(), aggregate, signature_set.message)) diff --git a/crates/bls/src/lib.rs b/crates/bls/src/lib.rs index 2e7a18a6..594be1e3 100644 --- a/crates/bls/src/lib.rs +++ b/crates/bls/src/lib.rs @@ -66,10 +66,12 @@ impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::MilagroError(_) => write!(f, "MilagroError"), - Error::InvalidByteLength { got, expected } => - write!(f, "InvalidByteLength {{ got: {got}, expected: {expected} }}"), - Error::InvalidSecretKeyLength { got, expected } => - write!(f, "InvalidSecretKeyLength {{ got: {got}, expected: {expected} }}"), + Error::InvalidByteLength { got, expected } => { + write!(f, "InvalidByteLength {{ got: {got}, expected: {expected} }}") + }, + Error::InvalidSecretKeyLength { got, expected } => { + write!(f, "InvalidSecretKeyLength {{ got: {got}, expected: {expected} }}") + }, Error::InvalidInfinityPublicKey => write!(f, "InvalidInfinityPublicKey"), Error::InvalidZeroSecretKey => write!(f, "InvalidZeroSecretKey"), } diff --git a/crates/bls/tests/tests.rs b/crates/bls/tests/tests.rs index 052fd35d..848e31d0 100644 --- a/crates/bls/tests/tests.rs +++ b/crates/bls/tests/tests.rs @@ -96,8 +96,8 @@ macro_rules! test_suite { #[test] fn partial_eq_infinity_agg_sig_and_real_agg_sig() { assert!( - AggregateSignature::infinity() != - AggregateSignatureTester::new_with_single_msg(1).sig + AggregateSignature::infinity() + != AggregateSignatureTester::new_with_single_msg(1).sig ) } diff --git a/crates/consensus-types/src/lib.rs b/crates/consensus-types/src/lib.rs index afff85a0..936b2056 100644 --- a/crates/consensus-types/src/lib.rs +++ b/crates/consensus-types/src/lib.rs @@ -49,7 +49,7 @@ pub fn compute_fork_version( fork_version: ForkVersion, ) -> Option { if epoch >= bellatrix_epoch { - return Some(fork_version) + return Some(fork_version); } None @@ -66,7 +66,7 @@ pub fn compute_fork_version_by_slot( // Compute floor of log2 of a u32. pub const fn floorlog2(x: u32) -> u32 { if x == 0 { - return 0 + return 0; } 31 - x.leading_zeros() } @@ -119,7 +119,7 @@ pub fn convert_branch(branch: &[H256]) -> Vec { pub fn validate_beacon_block_header_update(header_update: &HeaderUpdate) -> bool { let branch = convert_branch(&header_update.execution_hash_branch); if branch.len() != EXECUTION_PROOF_SIZE { - return false + return false; } let l2_proof = &branch[0..L2_EXECUTION_PAYLOAD_PROOF_SIZE]; diff --git a/crates/consensus-types/src/network_config.rs b/crates/consensus-types/src/network_config.rs index f12f71e0..3878347b 100644 --- a/crates/consensus-types/src/network_config.rs +++ b/crates/consensus-types/src/network_config.rs @@ -74,11 +74,11 @@ impl NetworkConfig { pub fn compute_fork_version(&self, epoch: Epoch) -> Option { if epoch >= self.capella_fork_epoch { - return Some(self.capella_fork_version) + return Some(self.capella_fork_version); } if epoch >= self.bellatrix_fork_epoch { - return Some(self.bellatrix_fork_version) + return Some(self.bellatrix_fork_version); } None diff --git a/crates/eth-rpc-client/src/beacon_rpc_client.rs b/crates/eth-rpc-client/src/beacon_rpc_client.rs index a5a006f5..ab6706a4 100644 --- a/crates/eth-rpc-client/src/beacon_rpc_client.rs +++ b/crates/eth-rpc-client/src/beacon_rpc_client.rs @@ -249,8 +249,9 @@ impl BeaconRPCClient { let light_client_snapshot_json_str = self.get_json_from_raw_request(&url).await?; let parsed_json: Value = serde_json::from_str(&light_client_snapshot_json_str)?; let beacon_header: BeaconBlockHeader = match self.routes.version { - BeaconRPCVersion::V1_5 => - serde_json::from_value(parsed_json["data"]["header"]["beacon"].clone())?, + BeaconRPCVersion::V1_5 => { + serde_json::from_value(parsed_json["data"]["header"]["beacon"].clone())? + }, _ => serde_json::from_value(parsed_json["data"]["header"].clone())?, }; @@ -358,7 +359,7 @@ impl BeaconRPCClient { trace!(target: "relay", "Beacon chain request: {}", url); let json_str = client.get(url).await?; if serde_json::from_str::(&json_str).is_err() { - return Err(FailOnGettingJson { response: json_str }.into()) + return Err(FailOnGettingJson { response: json_str }.into()); } Ok(json_str) @@ -453,13 +454,13 @@ impl BeaconRPCClient { .sync_committee_signature ) == serde_json::to_string(&sync_aggregate.sync_committee_signature)? { - break + break; } } signature_slot += 1; if signature_slot - attested_header.slot > CHECK_SLOTS_FORWARD_LIMIT { - return Err(SignatureSlotNotFoundError.into()) + return Err(SignatureSlotNotFoundError.into()); } } @@ -584,7 +585,7 @@ impl BeaconRPCClient { if parse_json.is_object() { if let Some(msg_str) = parse_json["message"].as_str() { if msg_str.contains("No block found for") { - return Err(NoBlockForSlotError.into()) + return Err(NoBlockForSlotError.into()); } } } diff --git a/crates/eth-rpc-client/src/eth1_rpc_client.rs b/crates/eth-rpc-client/src/eth1_rpc_client.rs index 7c206805..95a4c40b 100644 --- a/crates/eth-rpc-client/src/eth1_rpc_client.rs +++ b/crates/eth-rpc-client/src/eth1_rpc_client.rs @@ -64,7 +64,7 @@ impl Eth1RPCClient { let val: Value = serde_json::from_str(&res)?; let is_sync = val["result"].as_bool(); if let Some(is_sync_val) = is_sync { - return Ok(is_sync_val) + return Ok(is_sync_val); } Ok(true) diff --git a/crates/eth-rpc-client/src/execution_block_proof.rs b/crates/eth-rpc-client/src/execution_block_proof.rs index 60604fcc..35ef5763 100644 --- a/crates/eth-rpc-client/src/execution_block_proof.rs +++ b/crates/eth-rpc-client/src/execution_block_proof.rs @@ -107,7 +107,7 @@ impl ExecutionBlockProof { index: usize, ) -> Result { if branch.len() != depth { - return Err(IncorrectBranchLength) + return Err(IncorrectBranchLength); } let mut merkle_root = leaf.as_bytes().to_vec(); diff --git a/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs b/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs index 5c5cacd7..5b6363dc 100644 --- a/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs +++ b/crates/eth-rpc-client/src/hand_made_finality_light_client_update.rs @@ -116,12 +116,12 @@ impl HandMadeFinalityLightClientUpdate { sync_committee_bits.into_iter().map(|x| x.count_ones()).sum(); if sync_committee_bits_sum * 3 < (64 * 8 * 2) { current_attested_slot = signature_slot; - continue + continue; } if signature_beacon_body.attestations().is_empty() { current_attested_slot = signature_slot; - continue + continue; } let mut attested_slots: Vec = signature_beacon_body @@ -132,8 +132,8 @@ impl HandMadeFinalityLightClientUpdate { attested_slots.sort(); for i in (0..attested_slots.len()).rev() { - if (i == attested_slots.len() - 1 || attested_slots[i + 1] != attested_slots[i]) && - attested_slots[i] >= attested_slot + if (i == attested_slots.len() - 1 || attested_slots[i + 1] != attested_slots[i]) + && attested_slots[i] >= attested_slot { current_attested_slot = attested_slots[i]; @@ -142,10 +142,10 @@ impl HandMadeFinalityLightClientUpdate { .await { if err.downcast_ref::().is_none() { - return Err(err) + return Err(err); } } else { - return Ok((current_attested_slot, signature_slot)) + return Ok((current_attested_slot, signature_slot)); } } } diff --git a/crates/eth-rpc-client/src/utils.rs b/crates/eth-rpc-client/src/utils.rs index c35eea07..aea4927f 100644 --- a/crates/eth-rpc-client/src/utils.rs +++ b/crates/eth-rpc-client/src/utils.rs @@ -1,7 +1,7 @@ pub fn trim_quotes(s: String) -> String { let mut res_str = s; - if (res_str.starts_with('"') && res_str.ends_with('"')) || - (res_str.starts_with('\'') && res_str.ends_with('\'')) + if (res_str.starts_with('"') && res_str.ends_with('"')) + || (res_str.starts_with('\'') && res_str.ends_with('\'')) { res_str.pop(); res_str.remove(0); diff --git a/crates/eth-types/src/lib.rs b/crates/eth-types/src/lib.rs index 99daf36d..874e6544 100644 --- a/crates/eth-types/src/lib.rs +++ b/crates/eth-types/src/lib.rs @@ -250,7 +250,7 @@ impl RlpDecodable for BlockHeader { ); if block_header.hash.unwrap() != keccak256(serialized.as_raw()).into() { - return Err(RlpDecoderError::RlpInconsistentLengthAndData) + return Err(RlpDecoderError::RlpInconsistentLengthAndData); } block_header.partial_hash = Some( diff --git a/crates/eth2-pallet-init/src/init_pallet.rs b/crates/eth2-pallet-init/src/init_pallet.rs index 94a2fc1a..51cb48c0 100644 --- a/crates/eth2-pallet-init/src/init_pallet.rs +++ b/crates/eth2-pallet-init/src/init_pallet.rs @@ -23,7 +23,7 @@ pub fn verify_light_client_snapshot( format!("{:#x}", light_client_snapshot.beacon_header.tree_hash_root()); if block_root != expected_block_root { - return false + return false; } let branch = @@ -136,14 +136,14 @@ pub async fn init_pallet( info!(target: "relay", "init_block_root: {}", init_block_root); - if BeaconRPCClient::get_period_for_slot(light_client_snapshot.beacon_header.slot) != - BeaconRPCClient::get_period_for_slot(finality_slot) + if BeaconRPCClient::get_period_for_slot(light_client_snapshot.beacon_header.slot) + != BeaconRPCClient::get_period_for_slot(finality_slot) { panic!("Period for init_block_root different from current period. Please use snapshot for current period"); } if !verify_light_client_snapshot(init_block_root, &light_client_snapshot) { - return Err(InvalidLightClientSnapshot.into()) + return Err(InvalidLightClientSnapshot.into()); } let mut trusted_signature: Option = Option::None; @@ -245,9 +245,9 @@ mod tests { const MAX_GAP_IN_EPOCH_BETWEEN_FINALIZED_SLOTS: u64 = 3; assert!( - last_finalized_slot_eth_client + - ONE_EPOCH_IN_SLOTS * MAX_GAP_IN_EPOCH_BETWEEN_FINALIZED_SLOTS >= - last_finalized_slot_eth_network.as_u64() + last_finalized_slot_eth_client + + ONE_EPOCH_IN_SLOTS * MAX_GAP_IN_EPOCH_BETWEEN_FINALIZED_SLOTS + >= last_finalized_slot_eth_network.as_u64() ); } } diff --git a/crates/eth2-pallet-init/src/substrate_pallet_client.rs b/crates/eth2-pallet-init/src/substrate_pallet_client.rs index b4b8073b..649087ba 100644 --- a/crates/eth2-pallet-init/src/substrate_pallet_client.rs +++ b/crates/eth2-pallet-init/src/substrate_pallet_client.rs @@ -28,32 +28,42 @@ pub fn convert_typed_chain_ids( ) -> tangle::runtime_types::webb_proposals::header::TypedChainId { match t { TypedChainId::None => tangle::runtime_types::webb_proposals::header::TypedChainId::None, - TypedChainId::Evm(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::Evm(id), - TypedChainId::Substrate(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::Substrate(id), - TypedChainId::PolkadotParachain(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::PolkadotParachain(id), - TypedChainId::KusamaParachain(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::KusamaParachain(id), - TypedChainId::RococoParachain(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::RococoParachain(id), - TypedChainId::Cosmos(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::Cosmos(id), - TypedChainId::Solana(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::Solana(id), - TypedChainId::Ink(id) => - tangle::runtime_types::webb_proposals::header::TypedChainId::Ink(id), + TypedChainId::Evm(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::Evm(id) + }, + TypedChainId::Substrate(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::Substrate(id) + }, + TypedChainId::PolkadotParachain(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::PolkadotParachain(id) + }, + TypedChainId::KusamaParachain(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::KusamaParachain(id) + }, + TypedChainId::RococoParachain(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::RococoParachain(id) + }, + TypedChainId::Cosmos(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::Cosmos(id) + }, + TypedChainId::Solana(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::Solana(id) + }, + TypedChainId::Ink(id) => { + tangle::runtime_types::webb_proposals::header::TypedChainId::Ink(id) + }, _ => unimplemented!("Unsupported chain id"), } } pub fn convert_mode(t: tangle::runtime_types::eth_types::pallet::ClientMode) -> ClientMode { match t { - tangle::runtime_types::eth_types::pallet::ClientMode::SubmitLightClientUpdate => - ClientMode::SubmitLightClientUpdate, - tangle::runtime_types::eth_types::pallet::ClientMode::SubmitHeader => - ClientMode::SubmitHeader, + tangle::runtime_types::eth_types::pallet::ClientMode::SubmitLightClientUpdate => { + ClientMode::SubmitLightClientUpdate + }, + tangle::runtime_types::eth_types::pallet::ClientMode::SubmitHeader => { + ClientMode::SubmitHeader + }, } } @@ -190,7 +200,7 @@ impl EthClientPallet { std::io::ErrorKind::Other, format!("Failed to get hash storage value: {err:?}"), ) - .into()) + .into()); }, }; @@ -215,7 +225,7 @@ impl EthClientPallet { Ok(events) => { log::debug!("tx finalized"); let hash = events.extrinsic_hash(); - return Ok(hash.0.into()) + return Ok(hash.0.into()); }, Err(err) => { let error_msg = match err { @@ -234,7 +244,7 @@ impl EthClientPallet { std::io::ErrorKind::Other, format!("Tx failed : {error_msg}"), ) - .into()) + .into()); }, } }, @@ -309,7 +319,7 @@ impl EthClientPalletTrait for EthClientPallet { std::io::ErrorKind::Other, "Tried to submit empty headers".to_string(), ) - .into()) + .into()); } let mut txes = vec![]; diff --git a/crates/finality-update-verify/src/lib.rs b/crates/finality-update-verify/src/lib.rs index 918d19f9..77246e27 100644 --- a/crates/finality-update-verify/src/lib.rs +++ b/crates/finality-update-verify/src/lib.rs @@ -45,10 +45,10 @@ pub fn is_correct_finality_update( let sync_committee_bits_sum: u64 = sync_committee_bits.count_ones().try_into()?; if sync_committee_bits_sum < MIN_SYNC_COMMITTEE_PARTICIPANTS { - return Ok(false) + return Ok(false); } if sync_committee_bits_sum * 3 < (sync_committee_bits.len() * 2).try_into()? { - return Ok(false) + return Ok(false); } let participant_pubkeys = diff --git a/crates/lc-relay-types/src/lib.rs b/crates/lc-relay-types/src/lib.rs index e718513d..54ddd921 100644 --- a/crates/lc-relay-types/src/lib.rs +++ b/crates/lc-relay-types/src/lib.rs @@ -34,9 +34,9 @@ impl WebbRetryClient { if timeout_retries < self.timeout_retries && err.is_timeout() { timeout_retries += 1; tracing::error!(err = ?err, "retrying due to spurious network"); - continue + continue; } else { - return Err(err.into()) + return Err(err.into()); } } } @@ -59,9 +59,9 @@ impl WebbRetryClient { if timeout_retries < self.timeout_retries && err.is_timeout() { timeout_retries += 1; tracing::error!(err = ?err, "retrying due to spurious network"); - continue + continue; } else { - return Err(err.into()) + return Err(err.into()); } } } diff --git a/crates/lc-relayer-context/src/lib.rs b/crates/lc-relayer-context/src/lib.rs index 7824c273..6585e473 100644 --- a/crates/lc-relayer-context/src/lib.rs +++ b/crates/lc-relayer-context/src/lib.rs @@ -74,7 +74,7 @@ impl Shutdown { // If the shutdown signal has already been received, then return // immediately. if self.shutdown { - return + return; } // Cannot receive a "lag error" as only one value is ever sent. diff --git a/crates/merkle-proof/src/lib.rs b/crates/merkle-proof/src/lib.rs index c8da02b3..109aceed 100644 --- a/crates/merkle-proof/src/lib.rs +++ b/crates/merkle-proof/src/lib.rs @@ -57,7 +57,7 @@ impl MerkleTree { use MerkleTree::*; if leaves.is_empty() { - return Zero(depth) + return Zero(depth); } match depth { @@ -92,7 +92,7 @@ impl MerkleTree { use MerkleTree::*; if depth == 0 { - return Err(MerkleTreeError::DepthTooSmall) + return Err(MerkleTreeError::DepthTooSmall); } match self { @@ -256,7 +256,7 @@ mod tests { #[quickcheck] fn quickcheck_create_and_verify(int_leaves: Vec, depth: usize) -> TestResult { if depth > MAX_TREE_DEPTH || int_leaves.len() > 2usize.pow(depth as u32) { - return TestResult::discard() + return TestResult::discard(); } let leaves: Vec<_> = int_leaves.into_iter().map(H256::from_low_u64_be).collect(); @@ -274,7 +274,7 @@ mod tests { #[quickcheck] fn quickcheck_push_leaf_and_verify(int_leaves: Vec, depth: usize) -> TestResult { if depth == 0 || depth > MAX_TREE_DEPTH || int_leaves.len() > 2usize.pow(depth as u32) { - return TestResult::discard() + return TestResult::discard(); } let leaves_iter = int_leaves.into_iter().map(H256::from_low_u64_be); diff --git a/crates/serde-utils/src/fixed_bytes_hex.rs b/crates/serde-utils/src/fixed_bytes_hex.rs index bc6fef76..d06594ab 100644 --- a/crates/serde-utils/src/fixed_bytes_hex.rs +++ b/crates/serde-utils/src/fixed_bytes_hex.rs @@ -36,7 +36,7 @@ macro_rules! bytes_hex { "expected {} bytes for array, got {}", BYTES_LEN, decoded.len() - ))) + ))); } let mut array = [0; BYTES_LEN]; diff --git a/crates/serde-utils/src/u256_hex_be.rs b/crates/serde-utils/src/u256_hex_be.rs index bd904e7f..807aeeb5 100644 --- a/crates/serde-utils/src/u256_hex_be.rs +++ b/crates/serde-utils/src/u256_hex_be.rs @@ -26,7 +26,7 @@ impl<'de> Visitor<'de> for U256Visitor { E: de::Error, { if !value.starts_with("0x") { - return Err(de::Error::custom("must start with 0x")) + return Err(de::Error::custom("must start with 0x")); } let stripped = &value[2..]; if stripped.is_empty() { diff --git a/crates/serde-utils/src/u64_hex_be.rs b/crates/serde-utils/src/u64_hex_be.rs index 84e37042..7e8223b5 100644 --- a/crates/serde-utils/src/u64_hex_be.rs +++ b/crates/serde-utils/src/u64_hex_be.rs @@ -24,7 +24,7 @@ impl<'de> Visitor<'de> for QuantityVisitor { E: de::Error, { if !value.starts_with("0x") { - return Err(de::Error::custom("must start with 0x")) + return Err(de::Error::custom("must start with 0x")); } let stripped = value.trim_start_matches("0x"); @@ -68,7 +68,7 @@ where "expected max {} bytes for array, got {}", BYTES_LEN, decoded.len() - ))) + ))); } let mut array = [0; BYTES_LEN]; diff --git a/crates/serde-utils/src/u8_hex.rs b/crates/serde-utils/src/u8_hex.rs index 22d3686c..6ec3c6c4 100644 --- a/crates/serde-utils/src/u8_hex.rs +++ b/crates/serde-utils/src/u8_hex.rs @@ -20,7 +20,7 @@ where { let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; if bytes.len() != 1 { - return Err(D::Error::custom(format!("expected 1 byte for u8, got {}", bytes.len()))) + return Err(D::Error::custom(format!("expected 1 byte for u8, got {}", bytes.len()))); } Ok(bytes[0]) } diff --git a/crates/ssz-derive/src/lib.rs b/crates/ssz-derive/src/lib.rs index d02102e8..b26dc1ad 100644 --- a/crates/ssz-derive/src/lib.rs +++ b/crates/ssz-derive/src/lib.rs @@ -53,8 +53,9 @@ impl EnumBehaviour { s.map(|s| match s.as_ref() { ENUM_TRANSPARENT => EnumBehaviour::Transparent, ENUM_UNION => EnumBehaviour::Union, - other => - panic!("{} is an invalid enum_behaviour, use either {:?}", other, ENUM_VARIANTS), + other => { + panic!("{} is an invalid enum_behaviour, use either {:?}", other, ENUM_VARIANTS) + }, }) } } @@ -133,7 +134,7 @@ fn ssz_encode_derive_struct(derive_input: &DeriveInput, struct_data: &DataStruct for (ty, ident, field_opts) in parse_ssz_fields(struct_data) { if field_opts.skip_serializing { - continue + continue; } if let Some(module) = field_opts.with { @@ -427,7 +428,7 @@ fn ssz_decode_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Tok let #ident = <_>::default(); }); - continue + continue; } let is_ssz_fixed_len; diff --git a/crates/ssz/examples/struct_definition.rs b/crates/ssz/examples/struct_definition.rs index a80a3ecf..bc602c42 100644 --- a/crates/ssz/examples/struct_definition.rs +++ b/crates/ssz/examples/struct_definition.rs @@ -13,16 +13,16 @@ impl Encode for Foo { } fn ssz_bytes_len(&self) -> usize { - ::ssz_fixed_len() + - ssz::BYTES_PER_LENGTH_OFFSET + - ::ssz_fixed_len() + - self.b.ssz_bytes_len() + ::ssz_fixed_len() + + ssz::BYTES_PER_LENGTH_OFFSET + + ::ssz_fixed_len() + + self.b.ssz_bytes_len() } fn ssz_append(&self, buf: &mut Vec) { - let offset = ::ssz_fixed_len() + - as Encode>::ssz_fixed_len() + - ::ssz_fixed_len(); + let offset = ::ssz_fixed_len() + + as Encode>::ssz_fixed_len() + + ::ssz_fixed_len(); let mut encoder = SszEncoder::container(buf, offset); diff --git a/crates/ssz/src/decode.rs b/crates/ssz/src/decode.rs index 0212529e..9f3c4663 100644 --- a/crates/ssz/src/decode.rs +++ b/crates/ssz/src/decode.rs @@ -79,8 +79,8 @@ pub fn sanitize_offset( ) -> Result { if num_fixed_bytes.map_or(false, |fixed_bytes| offset < fixed_bytes) { Err(DecodeError::OffsetIntoFixedPortion(offset)) - } else if previous_offset.is_none() && - num_fixed_bytes.map_or(false, |fixed_bytes| offset != fixed_bytes) + } else if previous_offset.is_none() + && num_fixed_bytes.map_or(false, |fixed_bytes| offset != fixed_bytes) { Err(DecodeError::OffsetSkipsVariableBytes(offset)) } else if offset > num_bytes { @@ -217,8 +217,9 @@ impl<'a> SszDecoderBuilder<'a> { // fixed-length bytes. match first_offset.cmp(&self.items_index) { Ordering::Less => return Err(DecodeError::OffsetIntoFixedPortion(first_offset)), - Ordering::Greater => - return Err(DecodeError::OffsetSkipsVariableBytes(first_offset)), + Ordering::Greater => { + return Err(DecodeError::OffsetSkipsVariableBytes(first_offset)) + }, Ordering::Equal => (), } @@ -241,7 +242,7 @@ impl<'a> SszDecoderBuilder<'a> { return Err(DecodeError::InvalidByteLength { len: self.bytes.len(), expected: self.items_index, - }) + }); } } diff --git a/crates/ssz/src/decode/impls.rs b/crates/ssz/src/decode/impls.rs index 087ec674..59f1b3ae 100644 --- a/crates/ssz/src/decode/impls.rs +++ b/crates/ssz/src/decode/impls.rs @@ -475,14 +475,14 @@ pub fn decode_list_of_variable_length_items if bytes.is_empty() { return Container::try_from_iter(iter::empty()).map_err(|e| { DecodeError::BytesInvalid(format!("Error trying to collect empty list: {e:?}")) - }) + }); } let first_offset = read_offset(bytes)?; sanitize_offset(first_offset, None, bytes.len(), Some(first_offset))?; if first_offset % BYTES_PER_LENGTH_OFFSET != 0 || first_offset < BYTES_PER_LENGTH_OFFSET { - return Err(DecodeError::InvalidListFixedBytesLen(first_offset)) + return Err(DecodeError::InvalidListFixedBytesLen(first_offset)); } let num_items = first_offset / BYTES_PER_LENGTH_OFFSET; @@ -490,7 +490,7 @@ pub fn decode_list_of_variable_length_items if max_len.map_or(false, |max| num_items > max) { return Err(DecodeError::BytesInvalid(format!( "Variable length list of {num_items} items exceeds maximum of {max_len:?}" - ))) + ))); } let mut offset = first_offset; diff --git a/crates/ssz/src/legacy.rs b/crates/ssz/src/legacy.rs index 627d358e..3dff7888 100644 --- a/crates/ssz/src/legacy.rs +++ b/crates/ssz/src/legacy.rs @@ -93,7 +93,7 @@ macro_rules! four_byte_option_impl { return Err(DecodeError::InvalidByteLength { len: bytes.len(), expected: BYTES_PER_LENGTH_OFFSET, - }) + }); } let (index_bytes, value_bytes) = bytes.split_at(BYTES_PER_LENGTH_OFFSET); diff --git a/crates/tree-hash-derive/src/lib.rs b/crates/tree-hash-derive/src/lib.rs index 3ff718fc..56716381 100644 --- a/crates/tree-hash-derive/src/lib.rs +++ b/crates/tree-hash-derive/src/lib.rs @@ -42,8 +42,9 @@ impl EnumBehaviour { s.map(|s| match s.as_ref() { ENUM_TRANSPARENT => EnumBehaviour::Transparent, ENUM_UNION => EnumBehaviour::Union, - other => - panic!("{} is an invalid enum_behaviour, use either {:?}", other, ENUM_VARIANTS), + other => { + panic!("{} is an invalid enum_behaviour, use either {:?}", other, ENUM_VARIANTS) + }, }) } } @@ -114,8 +115,8 @@ fn cached_tree_hash_attr_metas(attrs: &[Attribute]) -> Vec { /// The field attribute is: `#[tree_hash(skip_hashing)]` fn should_skip_hashing(field: &syn::Field) -> bool { field.attrs.iter().any(|attr| { - attr.path.is_ident("tree_hash") && - attr.tokens.to_string().replace(' ', "") == "(skip_hashing)" + attr.path.is_ident("tree_hash") + && attr.tokens.to_string().replace(' ', "") == "(skip_hashing)" }) } diff --git a/crates/tree-hash/src/lib.rs b/crates/tree-hash/src/lib.rs index f2499f1f..ffe8857c 100644 --- a/crates/tree-hash/src/lib.rs +++ b/crates/tree-hash/src/lib.rs @@ -86,7 +86,7 @@ pub fn mix_in_length(root: &Hash256, length: usize) -> Hash256 { /// https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.3/ssz/simple-serialize.md#union pub fn mix_in_selector(root: &Hash256, selector: u8) -> Option { if selector > MAX_UNION_SELECTOR { - return None + return None; } let mut chunk = [0; BYTES_PER_CHUNK]; diff --git a/crates/tree-hash/src/merkle_hasher.rs b/crates/tree-hash/src/merkle_hasher.rs index 623a7f7f..ad92c9d4 100644 --- a/crates/tree-hash/src/merkle_hasher.rs +++ b/crates/tree-hash/src/merkle_hasher.rs @@ -238,7 +238,7 @@ impl MerkleHasher { let max_leaves = 1 << (self.depth + 1); if self.next_leaf > max_leaves { - return Err(Error::MaximumLeavesExceeded { max_leaves }) + return Err(Error::MaximumLeavesExceeded { max_leaves }); } else if self.next_leaf == 1 { // A tree of depth one has a root that is equal to the first given leaf. self.root = Some(Hash256::from_slice(leaf)) @@ -272,14 +272,14 @@ impl MerkleHasher { // If the tree is incomplete, we must complete it by providing zero-hashes. loop { if let Some(root) = self.root { - break Ok(root) + break Ok(root); } else if let Some(node) = self.half_nodes.last() { let right_child = node.id * 2 + 1; self.process_right_node(right_child, self.zero_hash(right_child)); } else if self.next_leaf == 1 { // The next_leaf can only be 1 if the tree has a depth of one. If have been no // leaves supplied, assume a root of zero. - break Ok(Hash256::zero()) + break Ok(Hash256::zero()); } else { // The only scenario where there are (a) no half nodes and (b) a tree of depth // two or more is where no leaves have been supplied at all. @@ -331,14 +331,14 @@ impl MerkleHasher { ); if parent == 1 { self.root = Some(Hash256::from_slice(preimage.as_bytes())); - break + break; } else { parent = get_parent(parent); } }, _ => { self.half_nodes.push(HalfNode::new(parent, preimage)); - break + break; }, } } diff --git a/crates/tree-hash/src/merkleize_padded.rs b/crates/tree-hash/src/merkleize_padded.rs index eb609444..8e29b1bc 100644 --- a/crates/tree-hash/src/merkleize_padded.rs +++ b/crates/tree-hash/src/merkleize_padded.rs @@ -38,7 +38,7 @@ pub fn merkleize_padded(bytes: &[u8], min_leaves: usize) -> Hash256 { if bytes.len() <= BYTES_PER_CHUNK && min_leaves <= 1 { let mut o = bytes.to_vec(); o.resize(BYTES_PER_CHUNK, 0); - return Hash256::from_slice(&o) + return Hash256::from_slice(&o); } assert!( diff --git a/crates/tree-hash/src/merkleize_standard.rs b/crates/tree-hash/src/merkleize_standard.rs index 7072daa1..79d2d1cd 100644 --- a/crates/tree-hash/src/merkleize_standard.rs +++ b/crates/tree-hash/src/merkleize_standard.rs @@ -24,7 +24,7 @@ pub fn merkleize_standard(bytes: &[u8]) -> Hash256 { if bytes.len() <= HASHSIZE { let mut o = bytes.to_vec(); o.resize(HASHSIZE, 0); - return Hash256::from_slice(&o[0..HASHSIZE]) + return Hash256::from_slice(&o[0..HASHSIZE]); } let leaves = num_sanitized_leaves(bytes.len()); diff --git a/eth2substrate-block-relay-rs/src/eth2substrate_relay.rs b/eth2substrate-block-relay-rs/src/eth2substrate_relay.rs index ec1cbd40..933ff96a 100644 --- a/eth2substrate-block-relay-rs/src/eth2substrate_relay.rs +++ b/eth2substrate-block-relay-rs/src/eth2substrate_relay.rs @@ -164,8 +164,8 @@ impl Eth2SubstrateRelay { { CHAIN_FINALIZED_EXECUTION_BLOCK_HEIGHT_ON_SUBSTRATE.inc_by(cmp::max( 0, - last_block_number as i64 - - CHAIN_FINALIZED_EXECUTION_BLOCK_HEIGHT_ON_SUBSTRATE.get(), + last_block_number as i64 + - CHAIN_FINALIZED_EXECUTION_BLOCK_HEIGHT_ON_SUBSTRATE.get(), )); } @@ -268,11 +268,11 @@ impl Eth2SubstrateRelay { headers.reverse(); if !self.submit_execution_blocks(headers).await { - return false + return false; } if min_block_number_in_batch == min_block_number { - break + break; } } @@ -280,8 +280,8 @@ impl Eth2SubstrateRelay { } async fn wait_for_synchronization(&self) -> anyhow::Result<()> { - while self.beacon_rpc_client.is_syncing().await? || - self.eth1_rpc_client.is_syncing().await? + while self.beacon_rpc_client.is_syncing().await? + || self.eth1_rpc_client.is_syncing().await? { info!(target: "relay", "Waiting for sync..."); tokio::time::sleep(Duration::from_secs(self.sleep_time_on_sync_secs)).await; @@ -403,17 +403,17 @@ impl Eth2SubstrateRelay { last_finalized_slot_on_substrate: u64, last_finalized_slot_on_eth: u64, ) -> bool { - if (last_finalized_slot_on_eth as i64) - (last_finalized_slot_on_substrate as i64) < - (ONE_EPOCH_IN_SLOTS * self.interval_between_light_client_updates_submission_in_epochs) + if (last_finalized_slot_on_eth as i64) - (last_finalized_slot_on_substrate as i64) + < (ONE_EPOCH_IN_SLOTS * self.interval_between_light_client_updates_submission_in_epochs) as i64 { info!(target: "relay", "Light client update were send less then {} epochs ago. Skipping sending light client update", self.interval_between_light_client_updates_submission_in_epochs); - return false + return false; } if last_finalized_slot_on_eth <= last_finalized_slot_on_substrate { info!(target: "relay", "Last finalized slot on Eth equal to last finalized slot on Substrate. Skipping sending light client update."); - return false + return false; } true @@ -447,7 +447,7 @@ impl Eth2SubstrateRelay { last_finalized_slot_on_eth, ) .await; - return true + return true; } false @@ -463,21 +463,22 @@ impl Eth2SubstrateRelay { if self.is_shot_run_mode() { info!(target: "relay", "Try sending light client update from file"); self.send_light_client_update_from_file().await; - return + return; } - if self.get_light_client_update_by_epoch && - self.send_regular_light_client_update_by_epoch( - last_finalized_slot_on_eth, - last_finalized_slot_on_near, - ) - .await + if self.get_light_client_update_by_epoch + && self + .send_regular_light_client_update_by_epoch( + last_finalized_slot_on_eth, + last_finalized_slot_on_near, + ) + .await { - return + return; } - if last_finalized_slot_on_eth >= - last_finalized_slot_on_near + self.max_blocks_for_finalization + if last_finalized_slot_on_eth + >= last_finalized_slot_on_near + self.max_blocks_for_finalization { info!(target: "relay", "Too big gap between slot of finalized block on NEAR and ETH. Sending hand made light client update"); self.send_hand_made_light_client_update(last_finalized_slot_on_near).await; @@ -562,10 +563,10 @@ impl Eth2SubstrateRelay { "Error on getting light client update. Skipping sending light client update", false ); - break res + break res; } - break res + break res; } warn!(target: "relay", "Error: {}", res.unwrap_err()); @@ -582,10 +583,10 @@ impl Eth2SubstrateRelay { last_finalized_slot_on_substrate: u64, ) -> anyhow::Result { const EXPECTED_EPOCHS_BETWEEN_HEAD_AND_FINALIZED_BLOCKS: u64 = 2; - let next_finalized_slot = last_finalized_slot_on_substrate + - self.interval_between_light_client_updates_submission_in_epochs * ONE_EPOCH_IN_SLOTS; - let attested_slot = next_finalized_slot + - EXPECTED_EPOCHS_BETWEEN_HEAD_AND_FINALIZED_BLOCKS * ONE_EPOCH_IN_SLOTS; + let next_finalized_slot = last_finalized_slot_on_substrate + + self.interval_between_light_client_updates_submission_in_epochs * ONE_EPOCH_IN_SLOTS; + let attested_slot = next_finalized_slot + + EXPECTED_EPOCHS_BETWEEN_HEAD_AND_FINALIZED_BLOCKS * ONE_EPOCH_IN_SLOTS; let attested_slot: u64 = self .beacon_rpc_client @@ -605,8 +606,8 @@ impl Eth2SubstrateRelay { ); let include_next_sync_committee = - BeaconRPCClient::get_period_for_slot(last_finalized_slot_on_substrate) != - BeaconRPCClient::get_period_for_slot(attested_slot); + BeaconRPCClient::get_period_for_slot(last_finalized_slot_on_substrate) + != BeaconRPCClient::get_period_for_slot(attested_slot); loop { let light_client_update = return_on_fail!( @@ -631,12 +632,12 @@ impl Eth2SubstrateRelay { .await, "Error on getting attested slot" ); - continue + continue; } trace!(target: "relay", "Hand made light client update: {:?}", light_client_update); self.send_specific_light_client_update(light_client_update).await; - return + return; } } @@ -654,7 +655,7 @@ impl Eth2SubstrateRelay { info!(target: "relay", "PASS bls signature verification!"); } else { warn!(target: "relay", "NOT PASS bls signature verification. Skip sending this light client update"); - return false + return false; } let execution_outcome = return_val_on_fail_and_sleep!( diff --git a/eth2substrate-block-relay-rs/src/test_utils.rs b/eth2substrate-block-relay-rs/src/test_utils.rs index 03907733..30bb60b4 100644 --- a/eth2substrate-block-relay-rs/src/test_utils.rs +++ b/eth2substrate-block-relay-rs/src/test_utils.rs @@ -77,7 +77,7 @@ pub async fn init_pallet_from_files( for header in &execution_blocks { if header.hash.unwrap() == finalized_hash { finalized_execution_header = Some(header.clone()); - break + break; } } diff --git a/gadget/src/lib.rs b/gadget/src/lib.rs index 0ed0200a..cceba31f 100644 --- a/gadget/src/lib.rs +++ b/gadget/src/lib.rs @@ -30,7 +30,7 @@ pub async fn ignite_lc_relayer(ctx: LightClientRelayerContext) -> anyhow::Result Ok(client) => client, Err(err) => { tracing::error!("Failed to connect with substrate client, retrying...!"); - return Err(backoff::Error::transient(err)) + return Err(backoff::Error::transient(err)); }, }; let api_client = Arc::new(api_client); @@ -59,7 +59,7 @@ pub async fn ignite_lc_relayer(ctx: LightClientRelayerContext) -> anyhow::Result Ok(_) => tracing::info!(target: "relay", "=== Pallet initialized ==="), Err(e) => { tracing::error!(target: "relay", "=== Failed to initialize pallet: {:?} ===", e); - return Err(backoff::Error::permanent(e)) + return Err(backoff::Error::permanent(e)); }, }; } @@ -75,14 +75,15 @@ pub async fn ignite_lc_relayer(ctx: LightClientRelayerContext) -> anyhow::Result pub async fn start_gadget(relayer_params: Eth2LightClientParams) { // Light Client Relayer let lc_relay_config = match relayer_params.lc_relay_config_path.as_ref() { - Some(p) => - loads_light_client_relayer_config(p).expect("failed to load light client config"), + Some(p) => { + loads_light_client_relayer_config(p).expect("failed to load light client config") + }, None => { tracing::error!( target: "light-client-gadget", "Error: Not Starting ETH2 Light Client Relayer Gadget. No Config Directory Specified" ); - return + return; }, }; @@ -94,7 +95,7 @@ pub async fn start_gadget(relayer_params: Eth2LightClientParams) { target: "light-client-gadget", "Error: Not Starting ETH2 Light Client Relayer Gadget. No Config Directory Specified" ); - return + return; }, }; let ctx = LightClientRelayerContext::new(lc_relay_config, lc_init_config); diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index fea41e7f..73f72416 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -63,6 +63,7 @@ fn development_config_genesis() -> RuntimeGenesisConfig { /// Development config (single validator Alice) pub fn development_config() -> ChainSpec { + #[allow(deprecated)] ChainSpec::from_genesis( "Development", "dev", @@ -89,6 +90,7 @@ fn local_testnet_genesis() -> RuntimeGenesisConfig { /// Local testnet config (multivalidator Alice + Bob) pub fn local_testnet_config() -> ChainSpec { + #[allow(deprecated)] ChainSpec::from_genesis( "Local Testnet", "local_testnet", diff --git a/node/src/command.rs b/node/src/command.rs index d33f1f49..94e6028c 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -42,8 +42,9 @@ impl SubstrateCli for Cli { Ok(match id { "dev" => Box::new(chain_spec::development_config()), "" | "local" => Box::new(chain_spec::local_testnet_config()), - path => - Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), + path => { + Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?) + }, }) } } @@ -117,7 +118,7 @@ pub fn run() -> sc_cli::Result<()> { "Runtime benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." .into(), - ) + ); } cmd.run::(config) @@ -166,8 +167,9 @@ pub fn run() -> sc_cli::Result<()> { cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) }, - BenchmarkCmd::Machine(cmd) => - cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), + BenchmarkCmd::Machine(cmd) => { + cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()) + }, } }) }, diff --git a/pallets/eth2-light-client/src/lib.rs b/pallets/eth2-light-client/src/lib.rs index b4ee965a..bd4d0fe5 100644 --- a/pallets/eth2-light-client/src/lib.rs +++ b/pallets/eth2-light-client/src/lib.rs @@ -76,8 +76,6 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -#![feature(slice_pattern)] - use eth_types::{ eth2::{ExtendedBeaconBlockHeader, LightClientState, LightClientUpdate, SyncCommittee}, pallet::{ClientMode, ExecutionHeaderInfo, InitInput}, @@ -395,8 +393,8 @@ pub mod pallet { let finalized_execution_header_hash = args.finalized_execution_header.calculate_hash(); ensure!( - finalized_execution_header_hash == - args.finalized_beacon_header.execution_block_hash, + finalized_execution_header_hash + == args.finalized_beacon_header.execution_block_hash, // Invalid execution block Error::::InvalidExecutionBlock, ); @@ -501,8 +499,8 @@ pub mod pallet { if let Some(diff_between_unfinalized_head_and_tail) = Self::get_diff_between_unfinalized_head_and_tail(typed_chain_id) { - let header_number_to_remove = (finalized_execution_header.block_number + - diff_between_unfinalized_head_and_tail) + let header_number_to_remove = (finalized_execution_header.block_number + + diff_between_unfinalized_head_and_tail) .saturating_sub(HashesGcThreshold::::get(typed_chain_id)); ensure!( @@ -607,12 +605,13 @@ impl Pallet { /// Returns finalized execution block hash pub fn block_hash_safe(typed_chain_id: TypedChainId, block_number: u64) -> Option { match Self::finalized_execution_header(typed_chain_id) { - Some(header) => + Some(header) => { if header.block_number >= block_number { Self::finalized_execution_blocks(typed_chain_id, block_number) } else { None - }, + } + }, None => None, } } @@ -686,12 +685,12 @@ impl Pallet { if Self::finalized_execution_blocks(typed_chain_id, header_number).is_some() { FinalizedExecutionBlocks::::remove(typed_chain_id, header_number); if header_number == 0 { - break + break; } else { header_number -= 1; } } else { - break + break; } } } @@ -701,8 +700,8 @@ impl Pallet { typed_chain_id: TypedChainId, ) -> Result<(), DispatchError> { ensure!( - ClientModeForChain::::get(typed_chain_id) == - Some(ClientMode::SubmitLightClientUpdate), + ClientModeForChain::::get(typed_chain_id) + == Some(ClientMode::SubmitLightClientUpdate), Error::::InvalidClientMode ); ensure!(!Paused::::get(typed_chain_id), Error::::LightClientUpdateNotAllowed); @@ -780,8 +779,8 @@ impl Pallet { ); ensure!( - update.attested_beacon_header.slot >= - update.finality_update.header_update.beacon_header.slot, + update.attested_beacon_header.slot + >= update.finality_update.header_update.beacon_header.slot, Error::::UpdateHeaderSlotLessThanFinalizedHeaderSlot ); diff --git a/pallets/eth2-light-client/src/tests.rs b/pallets/eth2-light-client/src/tests.rs index 2654ac50..4d69aafc 100644 --- a/pallets/eth2-light-client/src/tests.rs +++ b/pallets/eth2-light-client/src/tests.rs @@ -43,6 +43,7 @@ pub fn get_test_context( (headers, updates, init_input_0) } +#[cfg(test)] mod generic_tests { use super::*; use crate::{ @@ -97,8 +98,8 @@ mod generic_tests { for header in headers[0].iter().skip(1) { let header_hash = header.calculate_hash(); assert!( - Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() == - header_hash, + Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() + == header_hash, "Execution block hash is not finalized: {header_hash:?}" ); } @@ -160,8 +161,8 @@ mod generic_tests { for header in headers[0].iter().skip(1) { assert!( - Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() == - header.calculate_hash(), + Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() + == header.calculate_hash(), "Execution block hash is not finalized: {:?}", header.calculate_hash() ); @@ -186,8 +187,8 @@ mod generic_tests { for header in headers[1].iter() { assert!( - Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() == - header.calculate_hash(), + Eth2Client::block_hash_safe(GOERLI_CHAIN, header.number).unwrap_or_default() + == header.calculate_hash(), "Execution block hash is not finalized: {:?}", header.calculate_hash() ); @@ -488,6 +489,7 @@ mod generic_tests { } } +#[cfg(test)] mod mainnet_tests { use super::*; use crate::{ diff --git a/pallets/light-verifier/src/lib.rs b/pallets/light-verifier/src/lib.rs index 95c893af..9058b3cb 100644 --- a/pallets/light-verifier/src/lib.rs +++ b/pallets/light-verifier/src/lib.rs @@ -20,7 +20,6 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -#![feature(slice_pattern)] #![allow(unused)] use eth_types::BlockHeader; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 7c2dc37f..7c74a0d9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -402,8 +402,8 @@ impl Get> for OffchainRandomBalancing { max => { let seed = sp_io::offchain::random_seed(); let random = ::decode(&mut TrailingZeroInput::new(&seed)) - .expect("input is padded with zeroes; qed") % - max.saturating_add(1); + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); random as usize }, }; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5fe1a593..c38c8a87 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly" +channel = "stable" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From 093ac07b76c12bcb0f04033743ff0bc966ea82ce Mon Sep 17 00:00:00 2001 From: salman01zp Date: Wed, 6 Mar 2024 14:18:29 +0530 Subject: [PATCH 20/20] update CI jobs --- .github/workflows/validate_pr.yml | 46 +++++++++++++++++-------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml index d03eab5e..9b7a17c4 100644 --- a/.github/workflows/validate_pr.yml +++ b/.github/workflows/validate_pr.yml @@ -2,37 +2,41 @@ name: Test and Check on: push: - branches: - - main + branches: [main] pull_request: + branches: [main] + paths-ignore: + - "README.md" + + workflow_dispatch: jobs: test: concurrency: - group: clippy-${{ github.ref }} - cancel-in-progress: true + group: test-${{ github.ref }} + cancel-in-progress: true runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Install toolchain - id: toolchain - uses: actions-rs/toolchain@master - with: - profile: minimal - toolchain: stable - target: wasm32-unknown-unknown + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install toolchain + id: toolchain + uses: actions-rs/toolchain@master + with: + profile: minimal + toolchain: stable + target: wasm32-unknown-unknown - - name: Install protobuf-compiler - run: sudo apt-get install protobuf-compiler + - name: Install protobuf-compiler + run: sudo apt-get install protobuf-compiler - - name: Rust Cache - uses: Swatinem/rust-cache@v1.3.0 + - name: Rust Cache + uses: Swatinem/rust-cache@v1.3.0 - - name: Test workspace - run: cargo test --package pallet-eth2-light-client + - name: Test workspace + run: cargo test --package pallet-eth2-light-client rustfmt: concurrency: @@ -69,7 +73,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v1.3.0 - + - name: Install Protobuf run: sudo apt-get install protobuf-compiler