From 5dde91c2762677287a6f855c008353ebd1ea0d09 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Wed, 31 Jul 2024 14:30:22 +0200 Subject: [PATCH 01/13] Free finalized Ethereum updates (#159) * free finalized updates * update comment * fix check * fixes * tests * fixes * fmt * finishing touches * comments * adds missing impl * adds test * fixes * fix --- .github/workflows/parachain.yml | 356 ++++++++++++++++++ .../pallets/ethereum-client/src/lib.rs | 51 ++- .../pallets/ethereum-client/src/mock.rs | 1 + .../pallets/ethereum-client/src/tests.rs | 202 ++++++---- .../pallets/inbound-queue/src/mock.rs | 1 + .../snowbridge/runtime/test-common/src/lib.rs | 73 +++- .../src/bridge_to_ethereum_config.rs | 199 +++++++++- .../bridge-hub-rococo/tests/tests.rs | 10 +- .../src/bridge_to_ethereum_config.rs | 220 +++++++++++ 9 files changed, 1016 insertions(+), 97 deletions(-) create mode 100644 .github/workflows/parachain.yml create mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs diff --git a/.github/workflows/parachain.yml b/.github/workflows/parachain.yml new file mode 100644 index 000000000000..0df1fe3872a0 --- /dev/null +++ b/.github/workflows/parachain.yml @@ -0,0 +1,356 @@ +name: bridge + +on: + push: + paths: + - "bridges/snowbridge/**" + - "!bridges/snowbridge/README.md" + - "!bridges/snowbridge/LICENSE" + branches: + - snowbridge + pull_request: + workflow_dispatch: + +env: + FUZZ_MAX_LEN: 10000000000 + FUZZ_MAX_RUNS: 30000 + RUST_NIGHTLY: "2024-02-08" + +jobs: + format: + runs-on: snowbridge-runner + env: + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + RUSTFLAGS: -C debuginfo=1 + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@v2 + with: + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/cache@v1 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + - uses: actions/setup-node@v4.0.0 + with: + node-version: "18.x" + registry-url: "https://npm.pkg.github.com" + scope: "@paritytech" + - name: setup rust toolchain + run: | + rustup target add wasm32-unknown-unknown + curl -LO https://github.com/paritytech/rustc-rv32e-toolchain/releases/download/v1.1.0/rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst + tar -I zstd -xf rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst + mv rve-nightly ~/.rustup/toolchains/ + rustup toolchain install nightly + rustup component add rustfmt --toolchain nightly + rustup show + - name: format + run: > + cargo +nightly fmt + -p snowbridge-pallet-ethereum-client + -p snowbridge-pallet-inbound-queue + -p snowbridge-pallet-outbound-queue + -p snowbridge-outbound-queue-merkle-tree + -p snowbridge-pallet-system + -p snowbridge-beacon-primitives + -p snowbridge-core + -p snowbridge-ethereum + -p snowbridge-router-primitives + -p snowbridge-runtime-common + -p snowbridge-runtime-test-common + -p bridge-hub-rococo-runtime + -p bridge-hub-rococo-integration-tests + -p asset-hub-rococo-integration-tests + -p bridge-hub-westend-runtime + -p bridge-hub-westend-integration-tests + -p asset-hub-westend-integration-tests + -- + --check + - name: install taplo + run: | + cargo install taplo-cli --locked + - name: taplo + run: taplo format --check --config .config/taplo.toml + - name: install zepter + run: | + cargo install zepter -f --locked + - name: zepter + run: zepter run check + - name: lint-markdown + run: | + npm install -g markdownlint-cli + markdownlint --version + markdownlint --config .github/.markdownlint.yaml --ignore target + + check: + runs-on: snowbridge-runner + env: + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + RUSTFLAGS: -C debuginfo=1 + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@v2 + with: + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/cache@v1 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + - uses: actions/setup-node@v4.0.0 + with: + node-version: "18.x" + registry-url: "https://npm.pkg.github.com" + scope: "@paritytech" + - name: setup rust toolchain + run: | + rustup target add wasm32-unknown-unknown + curl -LO https://github.com/paritytech/rustc-rv32e-toolchain/releases/download/v1.1.0/rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst + tar -I zstd -xf rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst + mv rve-nightly ~/.rustup/toolchains/ + rustup toolchain install nightly + rustup component add rustfmt --toolchain nightly + rustup show + - name: cargo check + run: cargo check --workspace --all-features + - name: clippy + run: cargo clippy --all-features -- -D warnings + + test: + needs: check + runs-on: snowbridge-runner + env: + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + RUSTFLAGS: -C debuginfo=1 + SKIP_WASM_BUILD: 1 + RUST_MIN_STACK: 8388608 + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/cache@v1 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + - name: setup rust toolchain + run: rustup show + # Increase stack limit for beacon light client tests + - run: sudo prlimit --pid $$ --stack=32768 + # Run tests for runtime-benchmarks feature + - name: Tests for runtime-benchmarks + run: > + cargo test + -p snowbridge-pallet-ethereum-client + -p snowbridge-pallet-inbound-queue + -p snowbridge-pallet-outbound-queue + -p snowbridge-outbound-queue-merkle-tree + -p snowbridge-pallet-system + -p snowbridge-beacon-primitives + -p snowbridge-core + -p snowbridge-ethereum + -p snowbridge-router-primitives + -p snowbridge-runtime-common + --features runtime-benchmarks + # Run tests for all features + - name: Tests for all features + run: > + cargo test + -p snowbridge-pallet-ethereum-client + -p snowbridge-pallet-inbound-queue + -p snowbridge-pallet-outbound-queue + -p snowbridge-outbound-queue-merkle-tree + -p snowbridge-pallet-system + -p snowbridge-beacon-primitives + -p snowbridge-core + -p snowbridge-ethereum + -p snowbridge-router-primitives + -p snowbridge-runtime-common + --all-features + + coverage: + if: false + needs: check + runs-on: snowbridge-runner + env: + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + RUSTFLAGS: -C debuginfo=1 + SKIP_WASM_BUILD: 1 + RUST_MIN_STACK: 8388608 + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: setup rust toolchain + run: rustup show + - name: run coverage test + run: > + cargo install cargo-tarpaulin@0.27.0 && + cargo tarpaulin + --workspace + --engine llvm + --out xml + - name: Upload coverage reports to Codecov with GitHub Action + uses: codecov/codecov-action@v3 + with: + files: cobertura.xml + flags: rust + + check-cumulus: + runs-on: snowbridge-runner + steps: + - uses: actions/checkout@v2 + with: + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: setup rust toolchain + run: rustup show + - name: check bridge-hub fast-runtime + run: > + cargo check + --release --verbose + -p bridge-hub-rococo-runtime + -p bridge-hub-westend-runtime + --features fast-runtime + - name: check bridge-hub runtime-benchmarks + run: > + cargo check + --release --verbose + -p bridge-hub-rococo-runtime + -p bridge-hub-westend-runtime + --features runtime-benchmarks + - name: check bridge-hub try-runtime + run: > + cargo check + --release --verbose + -p bridge-hub-rococo-runtime + -p bridge-hub-westend-runtime + --features try-runtime + - name: check bridge-hub all features + run: > + cargo check + --release --verbose + -p bridge-hub-rococo-runtime + -p bridge-hub-westend-runtime + --all-features + - name: check asset-hub all features + run: > + cargo check + --release --verbose + -p asset-hub-rococo-runtime + -p asset-hub-westend-runtime + --all-features + + runtime-tests: + needs: check + runs-on: snowbridge-runner + steps: + - uses: actions/checkout@v2 + with: + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: setup rust toolchain + run: rustup show + - name: snowbridge runtime tests + run: > + RUST_LOG=xcm=trace cargo test + -p bridge-hub-rococo-runtime + -p bridge-hub-westend-runtime + --test snowbridge + -- --nocapture + + integration-tests: + needs: check + runs-on: snowbridge-runner + steps: + - uses: actions/checkout@v2 + with: + submodules: "true" + - uses: arduino/setup-protoc@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: setup rust toolchain + run: rustup show + - name: bridge-hub and asset-hub integration tests + run: > + RUST_LOG=xcm=trace cargo test + -p bridge-hub-rococo-integration-tests + -p asset-hub-rococo-integration-tests + -p bridge-hub-westend-integration-tests + -p asset-hub-westend-integration-tests + -- --nocapture + + beacon-fuzz: + if: false + needs: test + runs-on: snowbridge-runner + env: + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + RUSTFLAGS: -C debuginfo=1 + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + submodules: "true" + - uses: actions/cache@v1 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + - name: install nightly + run: rustup install --profile minimal nightly-$RUST_NIGHTLY + - name: Install cargo-fuzz from crates.io + uses: baptiste0928/cargo-install@v2 + with: + crate: cargo-fuzz + version: "^0.11.2" + - name: Fuzz force checkpoint extrinsic + run: > + cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_force_checkpoint -- + -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS + - name: Fuzz submit extrinsic + run: > + cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_submit -- + -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS + - name: Fuzz submit execution header extrinsic + run: > + cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_submit_execution_header -- + -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index 6894977c21f4..526313f8236e 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -33,7 +33,10 @@ mod tests; mod benchmarking; use frame_support::{ - dispatch::DispatchResult, pallet_prelude::OptionQuery, traits::Get, transactional, + dispatch::{DispatchResult, PostDispatchInfo}, + pallet_prelude::OptionQuery, + traits::Get, + transactional, }; use frame_system::ensure_signed; use snowbridge_beacon_primitives::{ @@ -82,6 +85,9 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; #[pallet::constant] type ForkVersions: Get; + /// Minimum gap between finalized headers for an update to be free. + #[pallet::constant] + type FreeHeadersInterval: Get; type WeightInfo: WeightInfo; } @@ -204,11 +210,10 @@ pub mod pallet { #[transactional] /// Submits a new finalized beacon header update. The update may contain the next /// sync committee. - pub fn submit(origin: OriginFor, update: Box) -> DispatchResult { + pub fn submit(origin: OriginFor, update: Box) -> DispatchResultWithPostInfo { ensure_signed(origin)?; ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - Self::process_update(&update)?; - Ok(()) + Self::process_update(&update) } /// Halt or resume all pallet operations. May only be called by root. @@ -280,10 +285,9 @@ pub mod pallet { Ok(()) } - pub(crate) fn process_update(update: &Update) -> DispatchResult { + pub(crate) fn process_update(update: &Update) -> DispatchResultWithPostInfo { Self::verify_update(update)?; - Self::apply_update(update)?; - Ok(()) + Self::apply_update(update) } /// References and strictly follows @@ -432,8 +436,9 @@ pub mod pallet { /// Reference and strictly follows DispatchResult { + /// SyncCommitteePrepared type. Stores the provided finalized header. Updates are free + /// if the certain conditions are met, least of which being a successful update. + fn apply_update(update: &Update) -> DispatchResultWithPostInfo { let latest_finalized_state = FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) .ok_or(Error::::NotBootstrapped)?; @@ -465,11 +470,17 @@ pub mod pallet { }); }; + let pays_fee = Self::check_refundable(update, latest_finalized_state.slot); + let actual_weight = match update.next_sync_committee_update { + None => T::WeightInfo::submit(), + Some(_) => T::WeightInfo::submit_with_sync_committee(), + }; + if update.finalized_header.slot > latest_finalized_state.slot { Self::store_finalized_header(update.finalized_header, update.block_roots_root)?; } - Ok(()) + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee }) } /// Computes the signing root for a given beacon header and domain. The hash tree root @@ -634,11 +645,29 @@ pub mod pallet { config::SLOTS_PER_EPOCH as u64, )); let domain_type = config::DOMAIN_SYNC_COMMITTEE.to_vec(); - // Domains are used for for seeds, for signatures, and for selecting aggregators. + // Domains are used for seeds, for signatures, and for selecting aggregators. let domain = Self::compute_domain(domain_type, fork_version, validators_root)?; // Hash tree root of SigningData - object root + domain let signing_root = Self::compute_signing_root(header, domain)?; Ok(signing_root) } + + /// Updates are free if the update is successful and the interval between the latest + /// finalized header in storage and the newly imported header is large enough. All + /// successful sync committee updates are free. + pub(super) fn check_refundable(update: &Update, latest_slot: u64) -> Pays { + // If the sync committee was successfully updated, the update may be free. + if update.next_sync_committee_update.is_some() { + return Pays::No; + } + + // If free headers are allowed and the latest finalized header is larger than the + // minimum slot interval, the header import transaction is free. + if update.finalized_header.slot >= latest_slot + T::FreeHeadersInterval::get() as u64 { + return Pays::No; + } + + Pays::Yes + } } } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index 96298d4fa896..b90e28c51f78 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -111,6 +111,7 @@ parameter_types! { impl ethereum_beacon_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32<96>; type WeightInfo = (); } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index c16743b75ea4..200d536018a5 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -1,21 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use crate::{ - functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader, - CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee, - SyncCommitteePrepared, -}; - -use crate::mock::{ - get_message_verification_payload, load_checkpoint_update_fixture, - load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, - load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, + functions::compute_period, + mock::{ + get_message_verification_payload, load_checkpoint_update_fixture, + load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, + load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, + }, + sync_committee_sum, verify_merkle_branch, BeaconHeader, CompactBeaconState, Error, + FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared, }; pub use crate::mock::*; use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT}; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, pallet_prelude::Pays}; use hex_literal::hex; use snowbridge_beacon_primitives::{ types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader, @@ -129,6 +128,23 @@ pub fn compute_domain_bls() { }); } +#[test] +pub fn may_refund_call_fee() { + let finalized_update = Box::new(load_next_finalized_header_update_fixture()); + let sync_committee_update = Box::new(load_sync_committee_update_fixture()); + new_tester().execute_with(|| { + // Not free, smaller than the allowed free header interval + assert_eq!( + EthereumBeaconClient::check_refundable(&finalized_update.clone(), 8190), + Pays::Yes + ); + // Is free, larger than the minimum interval + assert_eq!(EthereumBeaconClient::check_refundable(&finalized_update, 8000), Pays::No); + // Is free, valid sync committee update + assert_eq!(EthereumBeaconClient::check_refundable(&sync_committee_update, 8190), Pays::No); + }); +} + #[test] pub fn verify_merkle_branch_for_finalized_root() { new_tester().execute_with(|| { @@ -340,7 +356,9 @@ fn submit_update_in_current_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); let block_root: H256 = update.finalized_header.hash_tree_root().unwrap(); assert!(>::contains_key(block_root)); }); @@ -357,7 +375,9 @@ fn submit_update_with_sync_committee_in_current_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update)); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); }); } @@ -374,20 +394,21 @@ fn reject_submit_update_in_next_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - sync_committee_update.clone() - )); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + // check an update in the next period is rejected - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()), - Error::::SyncCommitteeUpdateRequired - ); + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_err!(second_result, Error::::SyncCommitteeUpdateRequired); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); + // submit update with next sync committee - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - next_sync_committee_update - )); + let third_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_sync_committee_update); + assert_ok!(third_result); + assert_eq!(third_result.unwrap().pays_fee, Pays::No); // check same header in the next period can now be submitted successfully assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); let block_root: H256 = update.finalized_header.clone().hash_tree_root().unwrap(); @@ -407,10 +428,9 @@ fn submit_update_with_invalid_header_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidHeaderMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidHeaderMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -426,10 +446,9 @@ fn submit_update_with_invalid_block_roots_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidBlockRootsRootMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidBlockRootsRootMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -447,10 +466,9 @@ fn submit_update_with_invalid_next_sync_committee_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidSyncCommitteeMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidSyncCommitteeMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -464,14 +482,14 @@ fn submit_update_with_skipped_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - sync_committee_update.clone() - )); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::SkippedSyncCommitteePeriod - ); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(second_result, Error::::SkippedSyncCommitteePeriod); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -487,9 +505,16 @@ fn submit_update_with_sync_committee_in_next_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone())); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); + assert_ok!(second_result); + assert_eq!(second_result.unwrap().pays_fee, Pays::No); let last_finalized_state = FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()).unwrap(); let last_synced_period = compute_period(last_finalized_state.slot); @@ -505,13 +530,12 @@ fn submit_update_with_sync_committee_invalid_signature_slot() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - // makes a invalid update with signature_slot should be more than attested_slot + // makes an invalid update with signature_slot should be more than attested_slot update.signature_slot = update.attested_header.slot; - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidUpdateSlot - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidUpdateSlot); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -525,10 +549,9 @@ fn submit_update_with_skipped_sync_committee_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_update), - Error::::SkippedSyncCommitteePeriod - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_update); + assert_err!(result, Error::::SkippedSyncCommitteePeriod); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -546,10 +569,9 @@ fn submit_irrelevant_update() { update.attested_header.slot = checkpoint.header.slot; update.signature_slot = checkpoint.header.slot + 1; - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::IrrelevantUpdate - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::IrrelevantUpdate); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -558,10 +580,9 @@ fn submit_update_with_missing_bootstrap() { let update = Box::new(load_next_finalized_header_update_fixture()); new_tester().execute_with(|| { - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::NotBootstrapped - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::NotBootstrapped); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -574,7 +595,9 @@ fn submit_update_with_invalid_sync_committee_update() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update)); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); // makes update with invalid next_sync_committee >::mutate(>::get(), |x| { @@ -586,10 +609,9 @@ fn submit_update_with_invalid_sync_committee_update() { let next_sync_committee = NextSyncCommitteeUpdate::default(); next_update.next_sync_committee_update = Some(next_sync_committee); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update), - Error::::InvalidSyncCommitteeUpdate - ); + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update); + assert_err!(second_result, Error::::InvalidSyncCommitteeUpdate); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -612,12 +634,15 @@ fn submit_finalized_header_update_with_too_large_gap() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), - Error::::InvalidFinalizedHeaderGap - ); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); + assert_err!(second_result, Error::::InvalidFinalizedHeaderGap); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -637,14 +662,41 @@ fn submit_finalized_header_update_with_gap_at_limit() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), + second_result, // The test should pass the InvalidFinalizedHeaderGap check, and will fail at the // next check, the merkle proof, because we changed the next_update slots. Error::::InvalidHeaderMerkleProof ); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); + }); +} + +#[test] +fn duplicate_sync_committee_updates_are_not_free() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let sync_committee_update = Box::new(load_sync_committee_update_fixture()); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + // Check that if the same update is submitted, the update is not free. + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update); + assert_err!(second_result, Error::::IrrelevantUpdate); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index a031676c6076..871df6d1e51b 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -88,6 +88,7 @@ parameter_types! { impl snowbridge_pallet_ethereum_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32<32>; type WeightInfo = (); } diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index 8f36313e360f..b157ad4356bd 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -12,7 +12,7 @@ use parachains_runtimes_test_utils::{ }; use snowbridge_core::{ChannelId, ParaId}; use snowbridge_pallet_ethereum_client_fixtures::*; -use sp_core::{H160, U256}; +use sp_core::{Get, H160, U256}; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating}; use xcm::{ @@ -466,23 +466,37 @@ pub fn ethereum_extrinsic( let initial_checkpoint = make_checkpoint(); let update = make_finalized_header_update(); let sync_committee_update = make_sync_committee_update(); + let mut invalid_update = make_finalized_header_update(); + let mut invalid_sync_committee_update = make_sync_committee_update(); + invalid_update.finalized_header.slot = 4354; + invalid_sync_committee_update.finalized_header.slot = 4354; let alice = Alice; let alice_account = alice.to_account_id(); >::mint_into( - &alice_account.into(), + &alice_account.clone().into(), 10_000_000_000_000_u128.saturated_into::>(), ) .unwrap(); + let balance_before = + >::free_balance(&alice_account.clone().into()); assert_ok!(>::force_checkpoint( RuntimeHelper::::root_origin(), - initial_checkpoint, + initial_checkpoint.clone(), )); + let balance_after_checkpoint = + >::free_balance(&alice_account.clone().into()); let update_call: ::RuntimeCall = snowbridge_pallet_ethereum_client::Call::::submit { - update: Box::new(*update), + update: Box::new(*update.clone()), + } + .into(); + + let invalid_update_call: ::RuntimeCall = + snowbridge_pallet_ethereum_client::Call::::submit { + update: Box::new(*invalid_update), } .into(); @@ -492,12 +506,63 @@ pub fn ethereum_extrinsic( } .into(); + let invalid_update_sync_committee_call: ::RuntimeCall = + snowbridge_pallet_ethereum_client::Call::::submit { + update: Box::new(*invalid_sync_committee_update), + } + .into(); + + // Finalized header update let update_outcome = construct_and_apply_extrinsic(alice, update_call.into()); assert_ok!(update_outcome); + let balance_after_update = + >::free_balance(&alice_account.clone().into()); + + // Invalid finalized header update + let invalid_update_outcome = + construct_and_apply_extrinsic(alice, invalid_update_call.into()); + assert_err!( + invalid_update_outcome, + snowbridge_pallet_ethereum_client::Error::::InvalidUpdateSlot + ); + let balance_after_invalid_update = + >::free_balance(&alice_account.clone().into()); + // Sync committee update let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); + let balance_after_sync_com_update = + >::free_balance(&alice_account.clone().into()); + + // Invalid sync committee update + let invalid_sync_committee_outcome = + construct_and_apply_extrinsic(alice, invalid_update_sync_committee_call.into()); + assert_err!( + invalid_sync_committee_outcome, + snowbridge_pallet_ethereum_client::Error::::InvalidUpdateSlot + ); + let balance_after_invalid_sync_com_update = + >::free_balance(&alice_account.clone().into()); + + // Assert paid operations are charged and free operations are free + // Checkpoint is a free operation + assert!(balance_before == balance_after_checkpoint); + let gap = + ::FreeHeadersInterval::get(); + // Large enough header gap is free + if update.finalized_header.slot >= initial_checkpoint.header.slot + gap as u64 { + assert!(balance_after_checkpoint == balance_after_update); + } else { + // Otherwise paid + assert!(balance_after_checkpoint > balance_after_update); + } + // An invalid update is paid + assert!(balance_after_update > balance_after_invalid_update); + // A successful sync committee update is free + assert!(balance_after_invalid_update == balance_after_sync_com_update); + // An invalid sync committee update is paid + assert!(balance_after_sync_com_update > balance_after_invalid_sync_com_update); }); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index 01a762d4b99f..a5d798835ac8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -14,9 +14,32 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::{xcm_config::UniversalLocation, Runtime}; -use snowbridge_router_primitives::outbound::EthereumBlobExporter; -use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; +#[cfg(not(feature = "runtime-benchmarks"))] +use crate::XcmRouter; +use crate::{ + xcm_config, xcm_config::UniversalLocation, Balances, EthereumInboundQueue, + EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, + TreasuryAccount, +}; +use parachains_common::{AccountId, Balance}; +use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; +use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; +use sp_core::H160; +use testnet_parachains_constants::rococo::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; + +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; +use sp_runtime::{ + traits::{ConstU32, ConstU8, Keccak256}, + FixedU128, +}; /// Exports message to the Ethereum Gateway contract. pub type SnowbridgeExporter = EthereumBlobExporter< @@ -25,3 +48,173 @@ pub type SnowbridgeExporter = EthereumBlobExporter< snowbridge_pallet_outbound_queue::Pallet, snowbridge_core::AgentIdOf, >; + +// Ethereum Bridge +parameter_types! { + pub storage EthereumGatewayAddress: H160 = H160(hex_literal::hex!("EDa338E4dC46038493b885327842fD3E301CaB39")); +} + +parameter_types! { + pub const CreateAssetCall: [u8;2] = [53, 0]; + pub const CreateAssetDeposit: u128 = (UNITS / 10) + EXISTENTIAL_DEPOSIT; + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, + multiplier: FixedU128::from_rational(1, 1), + }; +} + +impl snowbridge_pallet_inbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Verifier = snowbridge_pallet_ethereum_client::Pallet; + type Token = Balances; + #[cfg(not(feature = "runtime-benchmarks"))] + type XcmSender = XcmRouter; + #[cfg(feature = "runtime-benchmarks")] + type XcmSender = DoNothingRouter; + type ChannelLookup = EthereumSystem; + type GatewayAddress = EthereumGatewayAddress; + #[cfg(feature = "runtime-benchmarks")] + type Helper = Runtime; + type MessageConverter = MessageToXcm< + CreateAssetCall, + CreateAssetDeposit, + ConstU8, + AccountId, + Balance, + >; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type MaxMessageSize = ConstU32<2048>; + type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type AssetTransactor = ::AssetTransactor; +} + +impl snowbridge_pallet_outbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Hashing = Keccak256; + type MessageQueue = MessageQueue; + type Decimals = ConstU8<12>; + type MaxMessagePayloadSize = ConstU32<2048>; + type MaxMessagesPerBlock = ConstU32<32>; + type GasMeter = snowbridge_core::outbound::ConstantGasMeter; + type Balance = Balance; + type WeightToFee = WeightToFee; + type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type Channels = EthereumSystem; +} + +#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [0, 0, 0, 0], // 0x00000000 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 0, 0], // 0x01000000 + epoch: 0, + }, + bellatrix: Fork { + version: [2, 0, 0, 0], // 0x02000000 + epoch: 0, + }, + capella: Fork { + version: [3, 0, 0, 0], // 0x03000000 + epoch: 0, + }, + deneb: Fork { + version: [4, 0, 0, 0], // 0x04000000 + epoch: 0, + } + }; +} + +#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [144, 0, 0, 111], // 0x90000069 + epoch: 0, + }, + altair: Fork { + version: [144, 0, 0, 112], // 0x90000070 + epoch: 50, + }, + bellatrix: Fork { + version: [144, 0, 0, 113], // 0x90000071 + epoch: 100, + }, + capella: Fork { + version: [144, 0, 0, 114], // 0x90000072 + epoch: 56832, + }, + deneb: Fork { + version: [144, 0, 0, 115], // 0x90000073 + epoch: 132608, + }, + }; +} + +impl snowbridge_pallet_ethereum_client::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + // Free consensus update every epoch. Works out to be 225 updates per day. + type FreeHeadersInterval = ConstU32<32>; + type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; +} + +impl snowbridge_pallet_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OutboundQueue = EthereumOutboundQueue; + type SiblingOrigin = EnsureXcm; + type AgentIdOf = snowbridge_core::AgentIdOf; + type TreasuryAccount = TreasuryAccount; + type Token = Balances; + type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type DefaultPricingParameters = Parameters; + type InboundDeliveryCost = EthereumInboundQueue; +} + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmark_helpers { + use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; + use codec::Encode; + use snowbridge_beacon_primitives::BeaconHeader; + use snowbridge_pallet_inbound_queue::BenchmarkHelper; + use sp_core::H256; + use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; + + impl BenchmarkHelper for Runtime { + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); + } + } + + pub struct DoNothingRouter; + impl SendXcm for DoNothingRouter { + type Ticket = Xcm<()>; + + fn validate( + _dest: &mut Option, + xcm: &mut Option>, + ) -> SendResult { + Ok((xcm.clone().unwrap(), Assets::new())) + } + fn deliver(xcm: Xcm<()>) -> Result { + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + Ok(hash) + } + } + + impl snowbridge_pallet_system::BenchmarkHelper for () { + fn make_xcm_origin(location: Location) -> RuntimeOrigin { + RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location)) + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index ca0d89f038cb..c1965e1c8893 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -18,11 +18,13 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_common_config, bridge_to_bulletin_config, bridge_to_westend_config, + bridge_common_config, bridge_to_bulletin_config, + bridge_to_ethereum_config::EthereumGatewayAddress, + bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, - Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs new file mode 100644 index 000000000000..82651b11aa51 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -0,0 +1,220 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +#[cfg(not(feature = "runtime-benchmarks"))] +use crate::XcmRouter; +use crate::{ + xcm_config, + xcm_config::{TreasuryAccount, UniversalLocation}, + Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, + RuntimeEvent, TransactionByteFee, +}; +use parachains_common::{AccountId, Balance}; +use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; +use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; +use sp_core::H160; +use testnet_parachains_constants::westend::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; + +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; +use sp_runtime::{ + traits::{ConstU32, ConstU8, Keccak256}, + FixedU128, +}; + +/// Exports message to the Ethereum Gateway contract. +pub type SnowbridgeExporter = EthereumBlobExporter< + UniversalLocation, + EthereumNetwork, + snowbridge_pallet_outbound_queue::Pallet, + snowbridge_core::AgentIdOf, +>; + +// Ethereum Bridge +parameter_types! { + pub storage EthereumGatewayAddress: H160 = H160(hex_literal::hex!("EDa338E4dC46038493b885327842fD3E301CaB39")); +} + +parameter_types! { + pub const CreateAssetCall: [u8;2] = [53, 0]; + pub const CreateAssetDeposit: u128 = (UNITS / 10) + EXISTENTIAL_DEPOSIT; + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, + multiplier: FixedU128::from_rational(1, 1), + }; +} + +impl snowbridge_pallet_inbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Verifier = snowbridge_pallet_ethereum_client::Pallet; + type Token = Balances; + #[cfg(not(feature = "runtime-benchmarks"))] + type XcmSender = XcmRouter; + #[cfg(feature = "runtime-benchmarks")] + type XcmSender = DoNothingRouter; + type ChannelLookup = EthereumSystem; + type GatewayAddress = EthereumGatewayAddress; + #[cfg(feature = "runtime-benchmarks")] + type Helper = Runtime; + type MessageConverter = MessageToXcm< + CreateAssetCall, + CreateAssetDeposit, + ConstU8, + AccountId, + Balance, + >; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type MaxMessageSize = ConstU32<2048>; + type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type AssetTransactor = ::AssetTransactor; +} + +impl snowbridge_pallet_outbound_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Hashing = Keccak256; + type MessageQueue = MessageQueue; + type Decimals = ConstU8<12>; + type MaxMessagePayloadSize = ConstU32<2048>; + type MaxMessagesPerBlock = ConstU32<32>; + type GasMeter = snowbridge_core::outbound::ConstantGasMeter; + type Balance = Balance; + type WeightToFee = WeightToFee; + type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; + type PricingParameters = EthereumSystem; + type Channels = EthereumSystem; +} + +#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [0, 0, 0, 0], // 0x00000000 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 0, 0], // 0x01000000 + epoch: 0, + }, + bellatrix: Fork { + version: [2, 0, 0, 0], // 0x02000000 + epoch: 0, + }, + capella: Fork { + version: [3, 0, 0, 0], // 0x03000000 + epoch: 0, + }, + deneb: Fork { + version: [4, 0, 0, 0], // 0x04000000 + epoch: 0, + } + }; +} + +#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))] +parameter_types! { + pub const ChainForkVersions: ForkVersions = ForkVersions { + genesis: Fork { + version: [144, 0, 0, 111], // 0x90000069 + epoch: 0, + }, + altair: Fork { + version: [144, 0, 0, 112], // 0x90000070 + epoch: 50, + }, + bellatrix: Fork { + version: [144, 0, 0, 113], // 0x90000071 + epoch: 100, + }, + capella: Fork { + version: [144, 0, 0, 114], // 0x90000072 + epoch: 56832, + }, + deneb: Fork { + version: [144, 0, 0, 115], // 0x90000073 + epoch: 132608, + }, + }; +} + +impl snowbridge_pallet_ethereum_client::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32<32>; + type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; +} + +impl snowbridge_pallet_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OutboundQueue = EthereumOutboundQueue; + type SiblingOrigin = EnsureXcm; + type AgentIdOf = snowbridge_core::AgentIdOf; + type TreasuryAccount = TreasuryAccount; + type Token = Balances; + type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type DefaultPricingParameters = Parameters; + type InboundDeliveryCost = EthereumInboundQueue; +} + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmark_helpers { + use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; + use codec::Encode; + use snowbridge_beacon_primitives::BeaconHeader; + use snowbridge_pallet_inbound_queue::BenchmarkHelper; + use sp_core::H256; + use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; + + impl BenchmarkHelper for Runtime { + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); + } + } + + pub struct DoNothingRouter; + impl SendXcm for DoNothingRouter { + type Ticket = Xcm<()>; + + fn validate( + _dest: &mut Option, + xcm: &mut Option>, + ) -> SendResult { + Ok((xcm.clone().unwrap(), Assets::new())) + } + fn deliver(xcm: Xcm<()>) -> Result { + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + Ok(hash) + } + } + + impl snowbridge_pallet_system::BenchmarkHelper for () { + fn make_xcm_origin(location: Location) -> RuntimeOrigin { + RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location)) + } + } +} From e8e06161af00a9d3c976ae88305442cb366fd606 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Wed, 31 Jul 2024 15:08:24 +0200 Subject: [PATCH 02/13] cleanup --- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 194 +----------------- 1 file changed, 9 insertions(+), 185 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 02ef0b9c0c72..1938f018a0e7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -45,20 +45,13 @@ use bridge_runtime_common::extensions::{ refund_relayer_extension::RefundableParachain, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{ - gwei, meth, - outbound::{Command, Fee}, - AgentId, AllowSiblingsOnly, PricingParameters, Rewards, -}; -use snowbridge_router_primitives::inbound::MessageToXcm; use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{Block as BlockT, Keccak256}, + traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, + ApplyExtrinsicResult, }; #[cfg(feature = "std")] @@ -79,16 +72,13 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use testnet_parachains_constants::rococo::{ - consensus::*, currency::*, fee::WeightToFee, snowbridge::INBOUND_QUEUE_PALLET_INDEX, time::*, -}; +use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use bp_runtime::HeaderId; use bridge_hub_common::{ message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AggregateMessageOrigin, }; -use pallet_xcm::EnsureXcm; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use xcm::VersionedLocation; @@ -99,7 +89,11 @@ pub use sp_runtime::BuildStorage; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use rococo_runtime_constants::system_parachain::{ASSET_HUB_ID, BRIDGE_HUB_ID}; -use xcm::prelude::*; +use snowbridge_core::{ + outbound::{Command, Fee}, + AgentId, PricingParameters, +}; +use xcm::{latest::prelude::*, prelude::*}; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, @@ -114,8 +108,6 @@ use parachains_common::{ #[cfg(feature = "runtime-benchmarks")] use alloc::boxed::Box; -#[cfg(feature = "runtime-benchmarks")] -use benchmark_helpers::DoNothingRouter; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -518,174 +510,6 @@ impl pallet_utility::Config for Runtime { type WeightInfo = weights::pallet_utility::WeightInfo; } -// Ethereum Bridge -parameter_types! { - pub storage EthereumGatewayAddress: H160 = H160(hex_literal::hex!("EDa338E4dC46038493b885327842fD3E301CaB39")); -} - -parameter_types! { - pub const CreateAssetCall: [u8;2] = [53, 0]; - pub const CreateAssetDeposit: u128 = (UNITS / 10) + EXISTENTIAL_DEPOSIT; - pub Parameters: PricingParameters = PricingParameters { - exchange_rate: FixedU128::from_rational(1, 400), - fee_per_gas: gwei(20), - rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, - multiplier: FixedU128::from_rational(1, 1), - }; -} - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmark_helpers { - use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; - use codec::Encode; - use snowbridge_beacon_primitives::BeaconHeader; - use snowbridge_pallet_inbound_queue::BenchmarkHelper; - use sp_core::H256; - use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; - - impl BenchmarkHelper for Runtime { - fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { - EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); - } - } - - pub struct DoNothingRouter; - impl SendXcm for DoNothingRouter { - type Ticket = Xcm<()>; - - fn validate( - _dest: &mut Option, - xcm: &mut Option>, - ) -> SendResult { - Ok((xcm.clone().unwrap(), Assets::new())) - } - fn deliver(xcm: Xcm<()>) -> Result { - let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - Ok(hash) - } - } - - impl snowbridge_pallet_system::BenchmarkHelper for () { - fn make_xcm_origin(location: Location) -> RuntimeOrigin { - RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location)) - } - } -} - -impl snowbridge_pallet_inbound_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Verifier = snowbridge_pallet_ethereum_client::Pallet; - type Token = Balances; - #[cfg(not(feature = "runtime-benchmarks"))] - type XcmSender = XcmRouter; - #[cfg(feature = "runtime-benchmarks")] - type XcmSender = DoNothingRouter; - type ChannelLookup = EthereumSystem; - type GatewayAddress = EthereumGatewayAddress; - #[cfg(feature = "runtime-benchmarks")] - type Helper = Runtime; - type MessageConverter = MessageToXcm< - CreateAssetCall, - CreateAssetDeposit, - ConstU8, - AccountId, - Balance, - >; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type MaxMessageSize = ConstU32<2048>; - type WeightInfo = weights::snowbridge_pallet_inbound_queue::WeightInfo; - type PricingParameters = EthereumSystem; - type AssetTransactor = ::AssetTransactor; -} - -impl snowbridge_pallet_outbound_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Hashing = Keccak256; - type MessageQueue = MessageQueue; - type Decimals = ConstU8<12>; - type MaxMessagePayloadSize = ConstU32<2048>; - type MaxMessagesPerBlock = ConstU32<32>; - type GasMeter = snowbridge_core::outbound::ConstantGasMeter; - type Balance = Balance; - type WeightToFee = WeightToFee; - type WeightInfo = weights::snowbridge_pallet_outbound_queue::WeightInfo; - type PricingParameters = EthereumSystem; - type Channels = EthereumSystem; -} - -#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] -parameter_types! { - pub const ChainForkVersions: ForkVersions = ForkVersions { - genesis: Fork { - version: [0, 0, 0, 0], // 0x00000000 - epoch: 0, - }, - altair: Fork { - version: [1, 0, 0, 0], // 0x01000000 - epoch: 0, - }, - bellatrix: Fork { - version: [2, 0, 0, 0], // 0x02000000 - epoch: 0, - }, - capella: Fork { - version: [3, 0, 0, 0], // 0x03000000 - epoch: 0, - }, - deneb: Fork { - version: [4, 0, 0, 0], // 0x04000000 - epoch: 0, - } - }; -} - -#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))] -parameter_types! { - pub const ChainForkVersions: ForkVersions = ForkVersions { - genesis: Fork { - version: [144, 0, 0, 111], // 0x90000069 - epoch: 0, - }, - altair: Fork { - version: [144, 0, 0, 112], // 0x90000070 - epoch: 50, - }, - bellatrix: Fork { - version: [144, 0, 0, 113], // 0x90000071 - epoch: 100, - }, - capella: Fork { - version: [144, 0, 0, 114], // 0x90000072 - epoch: 56832, - }, - deneb: Fork { - version: [144, 0, 0, 115], // 0x90000073 - epoch: 132608, - }, - }; -} - -impl snowbridge_pallet_ethereum_client::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ForkVersions = ChainForkVersions; - type WeightInfo = weights::snowbridge_pallet_ethereum_client::WeightInfo; -} - -impl snowbridge_pallet_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OutboundQueue = EthereumOutboundQueue; - type SiblingOrigin = EnsureXcm; - type AgentIdOf = snowbridge_core::AgentIdOf; - type TreasuryAccount = TreasuryAccount; - type Token = Balances; - type WeightInfo = weights::snowbridge_pallet_system::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type DefaultPricingParameters = Parameters; - type InboundDeliveryCost = EthereumInboundQueue; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime From 8aa9d7e1bf537bc553f46d8f370dd139076de183 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Wed, 31 Jul 2024 15:18:35 +0200 Subject: [PATCH 03/13] more cleanup --- .github/workflows/parachain.yml | 356 ------------------ .../src/bridge_to_ethereum_config.rs | 220 ----------- 2 files changed, 576 deletions(-) delete mode 100644 .github/workflows/parachain.yml delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs diff --git a/.github/workflows/parachain.yml b/.github/workflows/parachain.yml deleted file mode 100644 index 0df1fe3872a0..000000000000 --- a/.github/workflows/parachain.yml +++ /dev/null @@ -1,356 +0,0 @@ -name: bridge - -on: - push: - paths: - - "bridges/snowbridge/**" - - "!bridges/snowbridge/README.md" - - "!bridges/snowbridge/LICENSE" - branches: - - snowbridge - pull_request: - workflow_dispatch: - -env: - FUZZ_MAX_LEN: 10000000000 - FUZZ_MAX_RUNS: 30000 - RUST_NIGHTLY: "2024-02-08" - -jobs: - format: - runs-on: snowbridge-runner - env: - CARGO_INCREMENTAL: 0 - RUST_BACKTRACE: 1 - RUSTFLAGS: -C debuginfo=1 - SKIP_WASM_BUILD: 1 - steps: - - uses: actions/checkout@v2 - with: - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/cache@v1 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - uses: actions/setup-node@v4.0.0 - with: - node-version: "18.x" - registry-url: "https://npm.pkg.github.com" - scope: "@paritytech" - - name: setup rust toolchain - run: | - rustup target add wasm32-unknown-unknown - curl -LO https://github.com/paritytech/rustc-rv32e-toolchain/releases/download/v1.1.0/rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst - tar -I zstd -xf rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst - mv rve-nightly ~/.rustup/toolchains/ - rustup toolchain install nightly - rustup component add rustfmt --toolchain nightly - rustup show - - name: format - run: > - cargo +nightly fmt - -p snowbridge-pallet-ethereum-client - -p snowbridge-pallet-inbound-queue - -p snowbridge-pallet-outbound-queue - -p snowbridge-outbound-queue-merkle-tree - -p snowbridge-pallet-system - -p snowbridge-beacon-primitives - -p snowbridge-core - -p snowbridge-ethereum - -p snowbridge-router-primitives - -p snowbridge-runtime-common - -p snowbridge-runtime-test-common - -p bridge-hub-rococo-runtime - -p bridge-hub-rococo-integration-tests - -p asset-hub-rococo-integration-tests - -p bridge-hub-westend-runtime - -p bridge-hub-westend-integration-tests - -p asset-hub-westend-integration-tests - -- - --check - - name: install taplo - run: | - cargo install taplo-cli --locked - - name: taplo - run: taplo format --check --config .config/taplo.toml - - name: install zepter - run: | - cargo install zepter -f --locked - - name: zepter - run: zepter run check - - name: lint-markdown - run: | - npm install -g markdownlint-cli - markdownlint --version - markdownlint --config .github/.markdownlint.yaml --ignore target - - check: - runs-on: snowbridge-runner - env: - CARGO_INCREMENTAL: 0 - RUST_BACKTRACE: 1 - RUSTFLAGS: -C debuginfo=1 - SKIP_WASM_BUILD: 1 - steps: - - uses: actions/checkout@v2 - with: - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/cache@v1 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - uses: actions/setup-node@v4.0.0 - with: - node-version: "18.x" - registry-url: "https://npm.pkg.github.com" - scope: "@paritytech" - - name: setup rust toolchain - run: | - rustup target add wasm32-unknown-unknown - curl -LO https://github.com/paritytech/rustc-rv32e-toolchain/releases/download/v1.1.0/rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst - tar -I zstd -xf rust-rve-nightly-2024-01-05-x86_64-unknown-linux-gnu.tar.zst - mv rve-nightly ~/.rustup/toolchains/ - rustup toolchain install nightly - rustup component add rustfmt --toolchain nightly - rustup show - - name: cargo check - run: cargo check --workspace --all-features - - name: clippy - run: cargo clippy --all-features -- -D warnings - - test: - needs: check - runs-on: snowbridge-runner - env: - CARGO_INCREMENTAL: 0 - RUST_BACKTRACE: 1 - RUSTFLAGS: -C debuginfo=1 - SKIP_WASM_BUILD: 1 - RUST_MIN_STACK: 8388608 - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/cache@v1 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - name: setup rust toolchain - run: rustup show - # Increase stack limit for beacon light client tests - - run: sudo prlimit --pid $$ --stack=32768 - # Run tests for runtime-benchmarks feature - - name: Tests for runtime-benchmarks - run: > - cargo test - -p snowbridge-pallet-ethereum-client - -p snowbridge-pallet-inbound-queue - -p snowbridge-pallet-outbound-queue - -p snowbridge-outbound-queue-merkle-tree - -p snowbridge-pallet-system - -p snowbridge-beacon-primitives - -p snowbridge-core - -p snowbridge-ethereum - -p snowbridge-router-primitives - -p snowbridge-runtime-common - --features runtime-benchmarks - # Run tests for all features - - name: Tests for all features - run: > - cargo test - -p snowbridge-pallet-ethereum-client - -p snowbridge-pallet-inbound-queue - -p snowbridge-pallet-outbound-queue - -p snowbridge-outbound-queue-merkle-tree - -p snowbridge-pallet-system - -p snowbridge-beacon-primitives - -p snowbridge-core - -p snowbridge-ethereum - -p snowbridge-router-primitives - -p snowbridge-runtime-common - --all-features - - coverage: - if: false - needs: check - runs-on: snowbridge-runner - env: - CARGO_INCREMENTAL: 0 - RUST_BACKTRACE: 1 - RUSTFLAGS: -C debuginfo=1 - SKIP_WASM_BUILD: 1 - RUST_MIN_STACK: 8388608 - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: setup rust toolchain - run: rustup show - - name: run coverage test - run: > - cargo install cargo-tarpaulin@0.27.0 && - cargo tarpaulin - --workspace - --engine llvm - --out xml - - name: Upload coverage reports to Codecov with GitHub Action - uses: codecov/codecov-action@v3 - with: - files: cobertura.xml - flags: rust - - check-cumulus: - runs-on: snowbridge-runner - steps: - - uses: actions/checkout@v2 - with: - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: setup rust toolchain - run: rustup show - - name: check bridge-hub fast-runtime - run: > - cargo check - --release --verbose - -p bridge-hub-rococo-runtime - -p bridge-hub-westend-runtime - --features fast-runtime - - name: check bridge-hub runtime-benchmarks - run: > - cargo check - --release --verbose - -p bridge-hub-rococo-runtime - -p bridge-hub-westend-runtime - --features runtime-benchmarks - - name: check bridge-hub try-runtime - run: > - cargo check - --release --verbose - -p bridge-hub-rococo-runtime - -p bridge-hub-westend-runtime - --features try-runtime - - name: check bridge-hub all features - run: > - cargo check - --release --verbose - -p bridge-hub-rococo-runtime - -p bridge-hub-westend-runtime - --all-features - - name: check asset-hub all features - run: > - cargo check - --release --verbose - -p asset-hub-rococo-runtime - -p asset-hub-westend-runtime - --all-features - - runtime-tests: - needs: check - runs-on: snowbridge-runner - steps: - - uses: actions/checkout@v2 - with: - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: setup rust toolchain - run: rustup show - - name: snowbridge runtime tests - run: > - RUST_LOG=xcm=trace cargo test - -p bridge-hub-rococo-runtime - -p bridge-hub-westend-runtime - --test snowbridge - -- --nocapture - - integration-tests: - needs: check - runs-on: snowbridge-runner - steps: - - uses: actions/checkout@v2 - with: - submodules: "true" - - uses: arduino/setup-protoc@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: setup rust toolchain - run: rustup show - - name: bridge-hub and asset-hub integration tests - run: > - RUST_LOG=xcm=trace cargo test - -p bridge-hub-rococo-integration-tests - -p asset-hub-rococo-integration-tests - -p bridge-hub-westend-integration-tests - -p asset-hub-westend-integration-tests - -- --nocapture - - beacon-fuzz: - if: false - needs: test - runs-on: snowbridge-runner - env: - CARGO_INCREMENTAL: 0 - RUST_BACKTRACE: 1 - RUSTFLAGS: -C debuginfo=1 - SKIP_WASM_BUILD: 1 - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - submodules: "true" - - uses: actions/cache@v1 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - name: install nightly - run: rustup install --profile minimal nightly-$RUST_NIGHTLY - - name: Install cargo-fuzz from crates.io - uses: baptiste0928/cargo-install@v2 - with: - crate: cargo-fuzz - version: "^0.11.2" - - name: Fuzz force checkpoint extrinsic - run: > - cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_force_checkpoint -- - -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS - - name: Fuzz submit extrinsic - run: > - cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_submit -- - -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS - - name: Fuzz submit execution header extrinsic - run: > - cd bridges/snowbridge/pallets/ethereum-beacon-client && cargo +nightly-$RUST_NIGHTLY fuzz run fuzz_submit_execution_header -- - -max_len=$FUZZ_MAX_LEN -runs=$FUZZ_MAX_RUNS diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs deleted file mode 100644 index 82651b11aa51..000000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus 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. - -// Cumulus 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 Cumulus. If not, see . - -#[cfg(not(feature = "runtime-benchmarks"))] -use crate::XcmRouter; -use crate::{ - xcm_config, - xcm_config::{TreasuryAccount, UniversalLocation}, - Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, - RuntimeEvent, TransactionByteFee, -}; -use parachains_common::{AccountId, Balance}; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; -use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; -use sp_core::H160; -use testnet_parachains_constants::westend::{ - currency::*, - fee::WeightToFee, - snowbridge::{EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, -}; - -#[cfg(feature = "runtime-benchmarks")] -use benchmark_helpers::DoNothingRouter; -use frame_support::{parameter_types, weights::ConstantMultiplier}; -use pallet_xcm::EnsureXcm; -use sp_runtime::{ - traits::{ConstU32, ConstU8, Keccak256}, - FixedU128, -}; - -/// Exports message to the Ethereum Gateway contract. -pub type SnowbridgeExporter = EthereumBlobExporter< - UniversalLocation, - EthereumNetwork, - snowbridge_pallet_outbound_queue::Pallet, - snowbridge_core::AgentIdOf, ->; - -// Ethereum Bridge -parameter_types! { - pub storage EthereumGatewayAddress: H160 = H160(hex_literal::hex!("EDa338E4dC46038493b885327842fD3E301CaB39")); -} - -parameter_types! { - pub const CreateAssetCall: [u8;2] = [53, 0]; - pub const CreateAssetDeposit: u128 = (UNITS / 10) + EXISTENTIAL_DEPOSIT; - pub Parameters: PricingParameters = PricingParameters { - exchange_rate: FixedU128::from_rational(1, 400), - fee_per_gas: gwei(20), - rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, - multiplier: FixedU128::from_rational(1, 1), - }; -} - -impl snowbridge_pallet_inbound_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Verifier = snowbridge_pallet_ethereum_client::Pallet; - type Token = Balances; - #[cfg(not(feature = "runtime-benchmarks"))] - type XcmSender = XcmRouter; - #[cfg(feature = "runtime-benchmarks")] - type XcmSender = DoNothingRouter; - type ChannelLookup = EthereumSystem; - type GatewayAddress = EthereumGatewayAddress; - #[cfg(feature = "runtime-benchmarks")] - type Helper = Runtime; - type MessageConverter = MessageToXcm< - CreateAssetCall, - CreateAssetDeposit, - ConstU8, - AccountId, - Balance, - >; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type MaxMessageSize = ConstU32<2048>; - type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; - type PricingParameters = EthereumSystem; - type AssetTransactor = ::AssetTransactor; -} - -impl snowbridge_pallet_outbound_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Hashing = Keccak256; - type MessageQueue = MessageQueue; - type Decimals = ConstU8<12>; - type MaxMessagePayloadSize = ConstU32<2048>; - type MaxMessagesPerBlock = ConstU32<32>; - type GasMeter = snowbridge_core::outbound::ConstantGasMeter; - type Balance = Balance; - type WeightToFee = WeightToFee; - type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; - type PricingParameters = EthereumSystem; - type Channels = EthereumSystem; -} - -#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] -parameter_types! { - pub const ChainForkVersions: ForkVersions = ForkVersions { - genesis: Fork { - version: [0, 0, 0, 0], // 0x00000000 - epoch: 0, - }, - altair: Fork { - version: [1, 0, 0, 0], // 0x01000000 - epoch: 0, - }, - bellatrix: Fork { - version: [2, 0, 0, 0], // 0x02000000 - epoch: 0, - }, - capella: Fork { - version: [3, 0, 0, 0], // 0x03000000 - epoch: 0, - }, - deneb: Fork { - version: [4, 0, 0, 0], // 0x04000000 - epoch: 0, - } - }; -} - -#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))] -parameter_types! { - pub const ChainForkVersions: ForkVersions = ForkVersions { - genesis: Fork { - version: [144, 0, 0, 111], // 0x90000069 - epoch: 0, - }, - altair: Fork { - version: [144, 0, 0, 112], // 0x90000070 - epoch: 50, - }, - bellatrix: Fork { - version: [144, 0, 0, 113], // 0x90000071 - epoch: 100, - }, - capella: Fork { - version: [144, 0, 0, 114], // 0x90000072 - epoch: 56832, - }, - deneb: Fork { - version: [144, 0, 0, 115], // 0x90000073 - epoch: 132608, - }, - }; -} - -impl snowbridge_pallet_ethereum_client::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ForkVersions = ChainForkVersions; - type FreeHeadersInterval = ConstU32<32>; - type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; -} - -impl snowbridge_pallet_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OutboundQueue = EthereumOutboundQueue; - type SiblingOrigin = EnsureXcm; - type AgentIdOf = snowbridge_core::AgentIdOf; - type TreasuryAccount = TreasuryAccount; - type Token = Balances; - type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type DefaultPricingParameters = Parameters; - type InboundDeliveryCost = EthereumInboundQueue; -} - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmark_helpers { - use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; - use codec::Encode; - use snowbridge_beacon_primitives::BeaconHeader; - use snowbridge_pallet_inbound_queue::BenchmarkHelper; - use sp_core::H256; - use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; - - impl BenchmarkHelper for Runtime { - fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { - EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); - } - } - - pub struct DoNothingRouter; - impl SendXcm for DoNothingRouter { - type Ticket = Xcm<()>; - - fn validate( - _dest: &mut Option, - xcm: &mut Option>, - ) -> SendResult { - Ok((xcm.clone().unwrap(), Assets::new())) - } - fn deliver(xcm: Xcm<()>) -> Result { - let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - Ok(hash) - } - } - - impl snowbridge_pallet_system::BenchmarkHelper for () { - fn make_xcm_origin(location: Location) -> RuntimeOrigin { - RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location)) - } - } -} From ea85bf5e8d71c1442b1c937bad0927978912996c Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Thu, 1 Aug 2024 10:47:55 +0200 Subject: [PATCH 04/13] import fix --- bridges/snowbridge/pallets/ethereum-client/src/mock.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index b90e28c51f78..d4aeae20650c 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -10,6 +10,7 @@ use sp_std::default::Default; use std::{fs::File, path::PathBuf}; type Block = frame_system::mocking::MockBlock; +use frame_support::traits::ConstU32; use sp_runtime::BuildStorage; fn load_fixture(basename: String) -> Result From 3c55dd80f18ef2a8a2e2b187f0c5ab4f8bd555e1 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Thu, 1 Aug 2024 11:27:01 +0200 Subject: [PATCH 05/13] prdoc --- prdoc/pr_5201.prdoc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 prdoc/pr_5201.prdoc diff --git a/prdoc/pr_5201.prdoc b/prdoc/pr_5201.prdoc new file mode 100644 index 000000000000..35918f903baa --- /dev/null +++ b/prdoc/pr_5201.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Snowbridge free consensus updates + +doc: + - audience: Runtime Dev + description: | + Allow free consensus updates to the Snowbridge Ethereum client if the headers are more than a certain + number of headers apart. + +crates: + - name: snowbridge-pallet-ethereum-client + bump: minor + - name: snowbridge-pallet-inbound-queue + bump: minor + - name: snowbridge-runtime-test-common + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor From e07082e33dd7ba9bcc9eae76fffa7f711efa8661 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Thu, 1 Aug 2024 12:52:24 +0200 Subject: [PATCH 06/13] prdoc bump corrections --- prdoc/pr_5201.prdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prdoc/pr_5201.prdoc b/prdoc/pr_5201.prdoc index 35918f903baa..67e40e6183d1 100644 --- a/prdoc/pr_5201.prdoc +++ b/prdoc/pr_5201.prdoc @@ -13,8 +13,8 @@ crates: - name: snowbridge-pallet-ethereum-client bump: minor - name: snowbridge-pallet-inbound-queue - bump: minor + bump: patch - name: snowbridge-runtime-test-common - bump: minor + bump: patch - name: bridge-hub-rococo-runtime - bump: minor + bump: major From 9391a36368e962f05a1987bff7e9dda82a54b9cf Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Fri, 2 Aug 2024 09:41:49 +0200 Subject: [PATCH 07/13] saturating add --- bridges/snowbridge/pallets/ethereum-client/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index 526313f8236e..e62aa83b9abf 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -663,7 +663,9 @@ pub mod pallet { // If free headers are allowed and the latest finalized header is larger than the // minimum slot interval, the header import transaction is free. - if update.finalized_header.slot >= latest_slot + T::FreeHeadersInterval::get() as u64 { + if update.finalized_header.slot >= + latest_slot.saturating_add(T::FreeHeadersInterval::get() as u64) + { return Pays::No; } From c0077e1fda489302e7ebea7bfe75dcd7765605c6 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Mon, 26 Aug 2024 09:29:21 +0200 Subject: [PATCH 08/13] Update bridges/snowbridge/pallets/ethereum-client/src/lib.rs Co-authored-by: Francisco Aguirre --- bridges/snowbridge/pallets/ethereum-client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index e62aa83b9abf..66df4c924806 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -437,7 +437,7 @@ pub mod pallet { /// Applies a finalized beacon header update to the beacon client. If a next sync committee /// is present in the update, verify the sync committee by converting it to a /// SyncCommitteePrepared type. Stores the provided finalized header. Updates are free - /// if the certain conditions are met, least of which being a successful update. + /// if the certain conditions specified in `check_refundable` are met. fn apply_update(update: &Update) -> DispatchResultWithPostInfo { let latest_finalized_state = FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) From ab8739cff56a96ad838020a451d9809b7f617d15 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 26 Aug 2024 10:18:30 +0200 Subject: [PATCH 09/13] pr comments --- .../pallets/ethereum-client/src/lib.rs | 4 ++-- .../pallets/ethereum-client/src/mock.rs | 4 +++- .../pallets/ethereum-client/src/tests.rs | 22 ++++++++++++++++--- .../src/bridge_to_ethereum_config.rs | 4 +++- prdoc/pr_5201.prdoc | 3 ++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index 66df4c924806..84b1476931c9 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -661,8 +661,8 @@ pub mod pallet { return Pays::No; } - // If free headers are allowed and the latest finalized header is larger than the - // minimum slot interval, the header import transaction is free. + // If the latest finalized header is larger than the minimum slot interval, the header + // import transaction is free. if update.finalized_header.slot >= latest_slot.saturating_add(T::FreeHeadersInterval::get() as u64) { diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index d4aeae20650c..be456565d407 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -109,10 +109,12 @@ parameter_types! { }; } +pub const FREE_SLOTS_INTERVAL: u32 = config::SLOTS_PER_EPOCH as u32; + impl ethereum_beacon_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type FreeHeadersInterval = ConstU32<96>; + type FreeHeadersInterval = ConstU32; type WeightInfo = (); } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 200d536018a5..82a3b8224470 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -133,15 +133,31 @@ pub fn may_refund_call_fee() { let finalized_update = Box::new(load_next_finalized_header_update_fixture()); let sync_committee_update = Box::new(load_sync_committee_update_fixture()); new_tester().execute_with(|| { + let free_headers_interval: u64 = crate::mock::FREE_SLOTS_INTERVAL as u64; // Not free, smaller than the allowed free header interval assert_eq!( - EthereumBeaconClient::check_refundable(&finalized_update.clone(), 8190), + EthereumBeaconClient::check_refundable( + &finalized_update.clone(), + finalized_update.finalized_header.slot + free_headers_interval + ), Pays::Yes ); // Is free, larger than the minimum interval - assert_eq!(EthereumBeaconClient::check_refundable(&finalized_update, 8000), Pays::No); + assert_eq!( + EthereumBeaconClient::check_refundable( + &finalized_update, + finalized_update.finalized_header.slot - (free_headers_interval + 2) + ), + Pays::No + ); // Is free, valid sync committee update - assert_eq!(EthereumBeaconClient::check_refundable(&sync_committee_update, 8190), Pays::No); + assert_eq!( + EthereumBeaconClient::check_refundable( + &sync_committee_update, + finalized_update.finalized_header.slot + ), + Pays::No + ); }); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index a5d798835ac8..6c0486c62fa6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -41,6 +41,8 @@ use sp_runtime::{ FixedU128, }; +pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32; + /// Exports message to the Ethereum Gateway contract. pub type SnowbridgeExporter = EthereumBlobExporter< UniversalLocation, @@ -163,7 +165,7 @@ impl snowbridge_pallet_ethereum_client::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; // Free consensus update every epoch. Works out to be 225 updates per day. - type FreeHeadersInterval = ConstU32<32>; + type FreeHeadersInterval = ConstU32; type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; } diff --git a/prdoc/pr_5201.prdoc b/prdoc/pr_5201.prdoc index 67e40e6183d1..a645bbc511b7 100644 --- a/prdoc/pr_5201.prdoc +++ b/prdoc/pr_5201.prdoc @@ -7,7 +7,8 @@ doc: - audience: Runtime Dev description: | Allow free consensus updates to the Snowbridge Ethereum client if the headers are more than a certain - number of headers apart. + number of headers apart. Relayers providing valid consensus updates are refunded for updates. Bridge + users are not affected. crates: - name: snowbridge-pallet-ethereum-client From 34dda839ef1e739ecca631fe48b6a486135aa452 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 26 Aug 2024 10:37:22 +0200 Subject: [PATCH 10/13] adds westend free headers conf --- .../bridge-hub-westend/src/bridge_to_ethereum_config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index 7922d3ed02b1..47b6006ed6c1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -42,6 +42,8 @@ use sp_runtime::{ FixedU128, }; +pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32; + /// Exports message to the Ethereum Gateway contract. pub type SnowbridgeExporter = EthereumBlobExporter< UniversalLocation, @@ -163,6 +165,7 @@ parameter_types! { impl snowbridge_pallet_ethereum_client::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32; type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo; } From ba9560a2f5da6986839997224f884328a08af00f Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 26 Aug 2024 11:58:53 +0200 Subject: [PATCH 11/13] fix prdoc --- prdoc/pr_5201.prdoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/prdoc/pr_5201.prdoc b/prdoc/pr_5201.prdoc index a645bbc511b7..a0c1bbfd2e41 100644 --- a/prdoc/pr_5201.prdoc +++ b/prdoc/pr_5201.prdoc @@ -12,10 +12,12 @@ doc: crates: - name: snowbridge-pallet-ethereum-client - bump: minor + bump: patch - name: snowbridge-pallet-inbound-queue bump: patch - name: snowbridge-runtime-test-common bump: patch - name: bridge-hub-rococo-runtime bump: major + - name: bridge-hub-westend-runtime + bump: major From 82f05de6e702a3eec8a21d7ed904f8998846fea2 Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 2 Sep 2024 20:30:32 +0200 Subject: [PATCH 12/13] fmt --- .../runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 61c4de136c07..6f6fc67bad91 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -18,7 +18,9 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_common_config, bridge_to_bulletin_config, bridge_to_ethereum_config::EthereumGatewayAddress, bridge_to_westend_config, + bridge_common_config, bridge_to_bulletin_config, + bridge_to_ethereum_config::EthereumGatewayAddress, + bridge_to_westend_config, xcm_config::{LocationToAccountId, RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, From dbea452ea9aa81547470b4b7f98454555f98bdbc Mon Sep 17 00:00:00 2001 From: claravanstaden Date: Mon, 2 Sep 2024 20:40:23 +0200 Subject: [PATCH 13/13] clippy --- .../runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 6f6fc67bad91..982c9fec6634 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -22,9 +22,9 @@ use bridge_hub_rococo_runtime::{ bridge_to_ethereum_config::EthereumGatewayAddress, bridge_to_westend_config, xcm_config::{LocationToAccountId, RelayNetwork, TokenLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, - Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode};