diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 60251d8f6..83d87e764 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,7 @@ updates: # Check for updates once a month schedule: interval: "monthly" + rebase-strategy: "disabled" labels: - "ci" - "not-breaking" diff --git a/.github/workflows/docker-runtime-draft.yml b/.github/workflows/docker-runtime-draft.yml index 8eb576984..bf32b322c 100644 --- a/.github/workflows/docker-runtime-draft.yml +++ b/.github/workflows/docker-runtime-draft.yml @@ -87,13 +87,13 @@ jobs: driver-opts: | image=moby/buildkit:master - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./docker/${{matrix.image}}.Dockerfile diff --git a/.github/workflows/e2e-test-bridge.yml b/.github/workflows/e2e-test-bridge.yml index 5790fd105..471bcf7e9 100644 --- a/.github/workflows/e2e-test-bridge.yml +++ b/.github/workflows/e2e-test-bridge.yml @@ -43,7 +43,7 @@ jobs: uses: ./.github/workflow-templates/bridge-e2e - name: Commit Action Status - uses: LouisBrunner/checks-action@v1.1.1 + uses: LouisBrunner/checks-action@v2.0.0 with: sha: ${{ steps.sharef.outputs.sha }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/prepare-binary.yml b/.github/workflows/prepare-binary.yml index 8073dadd3..62a36cde4 100644 --- a/.github/workflows/prepare-binary.yml +++ b/.github/workflows/prepare-binary.yml @@ -25,6 +25,10 @@ jobs: ref: ${{ github.event.inputs.sha }} - name: Setup Rust toolchain run: rustup show + - name: Install protoc + run: | + sudo apt-get update + sudo apt-get install protobuf-compiler - name: Build Node run: cargo build --profile=production --all - name: Save parachain binary @@ -81,13 +85,13 @@ jobs: driver-opts: | image=moby/buildkit:master - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./docker/${{matrix.image}}.Dockerfile @@ -104,7 +108,7 @@ jobs: org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }} - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/prepare-tanssi-relay-binary.yml b/.github/workflows/prepare-tanssi-relay-binary.yml index ee7ac0be2..33738f0ba 100644 --- a/.github/workflows/prepare-tanssi-relay-binary.yml +++ b/.github/workflows/prepare-tanssi-relay-binary.yml @@ -25,6 +25,10 @@ jobs: ref: ${{ github.event.inputs.sha }} - name: Setup Rust toolchain run: rustup show + - name: Install protoc + run: | + sudo apt-get update + sudo apt-get install protobuf-compiler - name: Build Node run: cargo build --profile=production -p tanssi-relay - name: Save dancelight binary @@ -81,13 +85,13 @@ jobs: driver-opts: | image=moby/buildkit:master - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./docker/${{matrix.image}}.Dockerfile @@ -104,7 +108,7 @@ jobs: org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }} - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-binary-tannsi-relay.yml b/.github/workflows/publish-binary-tannsi-relay.yml index a0f00275d..37c30c3ea 100644 --- a/.github/workflows/publish-binary-tannsi-relay.yml +++ b/.github/workflows/publish-binary-tannsi-relay.yml @@ -38,6 +38,10 @@ jobs: ref: ${{ github.event.inputs.to }} - name: Setup Rust toolchain run: rustup show + - name: Install protoc + run: | + sudo apt-get update + sudo apt-get install protobuf-compiler - name: Build Node run: cargo build --profile=production -p tanssi-relay - name: Save dancelight binary diff --git a/.github/workflows/publish-docker-runtime-containers.yml b/.github/workflows/publish-docker-runtime-containers.yml index a81d9d0da..d77faeeb7 100644 --- a/.github/workflows/publish-docker-runtime-containers.yml +++ b/.github/workflows/publish-docker-runtime-containers.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - name: Login to DockerHub - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-docker-runtime-tanssi.yml b/.github/workflows/publish-docker-runtime-tanssi.yml index 0ab5eb8ef..94562db39 100644 --- a/.github/workflows/publish-docker-runtime-tanssi.yml +++ b/.github/workflows/publish-docker-runtime-tanssi.yml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 - name: Login to DockerHub - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-docker-tannsi-relay.yml b/.github/workflows/publish-docker-tannsi-relay.yml index aee02e287..6437c9c6f 100644 --- a/.github/workflows/publish-docker-tannsi-relay.yml +++ b/.github/workflows/publish-docker-tannsi-relay.yml @@ -23,7 +23,7 @@ jobs: with: fetch-depth: 0 - name: Login to DockerHub - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 8d058c3bb..7fe7a21f7 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -25,7 +25,7 @@ jobs: with: fetch-depth: 0 - name: Login to DockerHub - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-runtime.yml b/.github/workflows/publish-runtime.yml index b3824428a..6b578aa02 100644 --- a/.github/workflows/publish-runtime.yml +++ b/.github/workflows/publish-runtime.yml @@ -98,7 +98,7 @@ jobs: with: ref: ${{ github.event.inputs.to }} - name: Login to DockerHub - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d08cf2108..bff7fef6d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -236,7 +236,7 @@ jobs: with: ref: ${{ needs.set-tags.outputs.git_ref }} - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.4 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Setup Variables shell: bash run: | @@ -382,7 +382,7 @@ jobs: with: ref: ${{ needs.set-tags.outputs.git_ref }} - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.4 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Setup Variables shell: bash run: | @@ -993,13 +993,13 @@ jobs: driver-opts: | image=moby/buildkit:master - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./docker/${{matrix.image}}.Dockerfile diff --git a/.github/workflows/run-zombienet-tests.yml b/.github/workflows/run-zombienet-tests.yml index 484d59ccf..61765a1fb 100644 --- a/.github/workflows/run-zombienet-tests.yml +++ b/.github/workflows/run-zombienet-tests.yml @@ -85,7 +85,7 @@ jobs: with: ref: ${{ needs.set-tags.outputs.git_ref }} - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.4 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Setup Variables shell: bash run: | diff --git a/Cargo.lock b/Cargo.lock index 871208c7f..58e720f3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1932,7 +1932,7 @@ checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" [[package]] name = "container-chain-frontier-node" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-io 1.13.0", "async-trait", @@ -2030,7 +2030,7 @@ dependencies = [ [[package]] name = "container-chain-simple-node" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-io 1.13.0", "async-trait", @@ -17855,7 +17855,7 @@ dependencies = [ [[package]] name = "tanssi-node" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-io 1.13.0", "async-trait", @@ -17957,7 +17957,7 @@ dependencies = [ [[package]] name = "tanssi-relay" -version = "0.11.0" +version = "0.12.0" dependencies = [ "color-eyre", "polkadot-core-primitives", @@ -18017,7 +18017,7 @@ dependencies = [ [[package]] name = "tanssi-relay-service" -version = "0.11.0" +version = "0.12.0" dependencies = [ "assert_matches", "async-io 1.13.0", diff --git a/chains/container-chains/nodes/frontier/Cargo.toml b/chains/container-chains/nodes/frontier/Cargo.toml index 42d9f624e..0d5a3437e 100644 --- a/chains/container-chains/nodes/frontier/Cargo.toml +++ b/chains/container-chains/nodes/frontier/Cargo.toml @@ -5,7 +5,7 @@ build = "build.rs" description = "Frontier container chain template node" edition = "2021" license = "GPL-3.0-only" -version = "0.11.0" +version = "0.12.0" [lints] workspace = true diff --git a/chains/container-chains/nodes/simple/Cargo.toml b/chains/container-chains/nodes/simple/Cargo.toml index 81d83ecfa..f51c24aa3 100644 --- a/chains/container-chains/nodes/simple/Cargo.toml +++ b/chains/container-chains/nodes/simple/Cargo.toml @@ -5,7 +5,7 @@ build = "build.rs" description = "Simple container-chain template node" edition = "2021" license = "GPL-3.0-only" -version = "0.11.0" +version = "0.12.0" [lints] workspace = true diff --git a/chains/container-chains/runtime-templates/frontier/src/lib.rs b/chains/container-chains/runtime-templates/frontier/src/lib.rs index 44edb011d..ccf6cbfbb 100644 --- a/chains/container-chains/runtime-templates/frontier/src/lib.rs +++ b/chains/container-chains/runtime-templates/frontier/src/lib.rs @@ -332,7 +332,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("frontier-template"), impl_name: create_runtime_str!("frontier-template"), authoring_version: 1, - spec_version: 1100, + spec_version: 1200, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/chains/container-chains/runtime-templates/simple/src/lib.rs b/chains/container-chains/runtime-templates/simple/src/lib.rs index 013c09844..a737372e0 100644 --- a/chains/container-chains/runtime-templates/simple/src/lib.rs +++ b/chains/container-chains/runtime-templates/simple/src/lib.rs @@ -225,7 +225,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("container-chain-template"), impl_name: create_runtime_str!("container-chain-template"), authoring_version: 1, - spec_version: 1100, + spec_version: 1200, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/chains/orchestrator-paras/node/Cargo.toml b/chains/orchestrator-paras/node/Cargo.toml index 20e8930a4..1aa04e149 100644 --- a/chains/orchestrator-paras/node/Cargo.toml +++ b/chains/orchestrator-paras/node/Cargo.toml @@ -5,7 +5,7 @@ build = "build.rs" description = "Tanssi node implementation" edition = "2021" license = "GPL-3.0-only" -version = "0.11.0" +version = "0.12.0" [lints] workspace = true diff --git a/chains/orchestrator-paras/runtime/dancebox/src/lib.rs b/chains/orchestrator-paras/runtime/dancebox/src/lib.rs index 80217ec8c..1e3cc8430 100644 --- a/chains/orchestrator-paras/runtime/dancebox/src/lib.rs +++ b/chains/orchestrator-paras/runtime/dancebox/src/lib.rs @@ -252,7 +252,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("dancebox"), impl_name: create_runtime_str!("dancebox"), authoring_version: 1, - spec_version: 1100, + spec_version: 1200, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/chains/orchestrator-paras/runtime/flashbox/src/lib.rs b/chains/orchestrator-paras/runtime/flashbox/src/lib.rs index 17678bd29..b5250bd66 100644 --- a/chains/orchestrator-paras/runtime/flashbox/src/lib.rs +++ b/chains/orchestrator-paras/runtime/flashbox/src/lib.rs @@ -228,7 +228,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("flashbox"), impl_name: create_runtime_str!("flashbox"), authoring_version: 1, - spec_version: 1100, + spec_version: 1200, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/chains/orchestrator-relays/node/tanssi-relay-service/Cargo.toml b/chains/orchestrator-relays/node/tanssi-relay-service/Cargo.toml index c066b3d17..939ab719a 100644 --- a/chains/orchestrator-relays/node/tanssi-relay-service/Cargo.toml +++ b/chains/orchestrator-relays/node/tanssi-relay-service/Cargo.toml @@ -4,7 +4,7 @@ authors = { workspace = true } description = "Utils to tie different Tanssi components together and allow instantiation of a node." edition = "2021" license = "GPL-3.0-only" -version = "0.11.0" +version = "0.12.0" [lints] workspace = true diff --git a/chains/orchestrator-relays/node/tanssi-relay/Cargo.toml b/chains/orchestrator-relays/node/tanssi-relay/Cargo.toml index c9ed536e1..5e3420e80 100644 --- a/chains/orchestrator-relays/node/tanssi-relay/Cargo.toml +++ b/chains/orchestrator-relays/node/tanssi-relay/Cargo.toml @@ -5,7 +5,7 @@ description = "Implementation of a `https://tanssi.network` node in Rust based o edition = "2021" license = "GPL-3.0-only" readme = "README.md" -version = "0.11.0" +version = "0.12.0" [[bin]] name = "tanssi-relay" diff --git a/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs b/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs index 93cd42754..5b2f513a7 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs @@ -437,6 +437,7 @@ fn dancelight_testnet_genesis( x.stash.clone() }) .collect::>(), + ..Default::default() }, }) } diff --git a/chains/orchestrator-relays/runtime/dancelight/src/lib.rs b/chains/orchestrator-relays/runtime/dancelight/src/lib.rs index 67268b1bb..8459a7d48 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/lib.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/lib.rs @@ -193,7 +193,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("dancelight"), impl_name: create_runtime_str!("tanssi-dancelight-v2.0"), authoring_version: 0, - spec_version: 1100, + spec_version: 1200, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -467,6 +467,7 @@ impl pallet_babe::Config for Runtime { // session module is the trigger type EpochChangeTrigger = pallet_babe::ExternalTrigger; type DisabledValidators = Session; + // Not benchmarked in Kusama type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = ConstU32<0>; @@ -570,6 +571,10 @@ impl pallet_session::Config for Runtime { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; + // TODO: Current benchmarking code for pallet_session requires that the runtime + // uses pallet_staking, which we don't use. We need to make a PR to Substrate to + // allow decoupling the benchmark from other pallets. + // See https://github.com/paritytech/polkadot-sdk/blob/0845044454c005b577eab7afaea18583bd7e3dd3/substrate/frame/session/benchmarking/src/inner.rs#L38 type WeightInfo = (); } @@ -682,6 +687,7 @@ parameter_types! { impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; + // Not benchmarked in Kusama, benchmarking code also don't match WeightInfo trait. type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = ConstU32<0>; @@ -1292,6 +1298,8 @@ impl pallet_beefy::Config for Runtime { type MaxNominators = ConstU32<0>; type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = BeefyMmrLeaf; + // There are currently no benchmarks for pallet_beefy. + // https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/beefy/src type WeightInfo = (); type KeyOwnerProof = >::Proof; type EquivocationReportSystem = @@ -1313,7 +1321,7 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; type Hashing = Keccak256; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); + type WeightInfo = weights::pallet_mmr::SubstrateWeight; type LeafData = pallet_beefy_mmr::Pallet; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; #[cfg(feature = "runtime-benchmarks")] @@ -1359,7 +1367,7 @@ impl pallet_beefy_mmr::Config for Runtime { type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; type LeafExtra = LeafExtraData; type BeefyDataProvider = LeafExtraDataProvider; - type WeightInfo = (); + type WeightInfo = weights::pallet_beefy_mmr::SubstrateWeight; } impl paras_sudo_wrapper::Config for Runtime {} @@ -1541,7 +1549,7 @@ impl pallet_configuration::Config for Runtime { type SessionIndex = SessionIndex; type CurrentSessionIndex = CurrentSessionIndexGetter; type ForceEmptyOrchestrator = ConstBool; - type WeightInfo = (); + type WeightInfo = weights::pallet_configuration::SubstrateWeight; } impl pallet_migrations::Config for Runtime { @@ -1566,7 +1574,7 @@ impl pallet_multiblock_migrations::Config for Runtime { type MigrationStatusHandler = (); type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; type MaxServiceWeight = MbmServiceWeight; - type WeightInfo = (); + type WeightInfo = weights::pallet_multiblock_migrations::SubstrateWeight; } pub const FIXED_BLOCK_PRODUCTION_COST: u128 = 1 * MICROUNITS; @@ -2303,6 +2311,10 @@ mod benches { [pallet_asset_rate, AssetRate] [pallet_whitelist, Whitelist] [pallet_services_payment, ServicesPayment] + [pallet_mmr, Mmr] + [pallet_beefy_mmr, BeefyMmrLeaf] + [pallet_multiblock_migrations, MultiBlockMigrations] + // Tanssi [pallet_author_noting, AuthorNoting] [pallet_registrar, ContainerRegistrar] @@ -2313,6 +2325,7 @@ mod benches { [pallet_invulnerables, TanssiInvulnerables] [pallet_data_preservers, DataPreservers] [pallet_pooled_staking, PooledStaking] + [pallet_configuration, CollatorConfiguration] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs index aa85fdb91..cc44c0f06 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs @@ -18,8 +18,8 @@ use { crate::{ - BlockProductionCost, CollatorAssignmentCost, ExternalValidatorSlashes, MessageQueue, - RuntimeCall, + Authorship, BlockProductionCost, CollatorAssignmentCost, ExternalValidatorSlashes, + MessageQueue, RuntimeCall, }, babe_primitives::{ digests::{PreDigest, SecondaryPlainPreDigest}, @@ -250,6 +250,7 @@ pub fn start_block() -> RunSummary { // Initialize the new block Babe::on_initialize(System::block_number()); + Authorship::on_initialize(System::block_number()); ContainerRegistrar::on_initialize(System::block_number()); ExternalValidatorSlashes::on_initialize(System::block_number()); Session::on_initialize(System::block_number()); @@ -280,6 +281,7 @@ pub fn end_block() { advance_block_state_machine(RunBlockState::End(block_number)); // Finalize the block Babe::on_finalize(System::block_number()); + Authorship::on_finalize(System::block_number()); Session::on_finalize(System::block_number()); Grandpa::on_finalize(System::block_number()); TransactionPayment::on_finalize(System::block_number()); @@ -335,6 +337,8 @@ pub struct ExtBuilder { balances: Vec<(AccountId, Balance)>, // [validator, amount] validators: Vec<(AccountId, Balance)>, + // [validator, amount] + external_validators: Vec<(AccountId, Balance)>, // [collator, amount] collators: Vec<(AccountId, Balance)>, // sudo key @@ -362,6 +366,7 @@ impl Default for ExtBuilder { (AccountId::from(ALICE), 210 * UNIT), (AccountId::from(BOB), 100 * UNIT), ], + external_validators: vec![], collators: Default::default(), sudo: Default::default(), para_ids: Default::default(), @@ -398,6 +403,11 @@ impl ExtBuilder { self } + pub fn with_external_validators(mut self, validators: Vec<(AccountId, Balance)>) -> Self { + self.external_validators = validators; + self + } + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { self.collators = collators; self @@ -614,6 +624,32 @@ impl ExtBuilder { keys.extend(validator_keys) } + if !self.external_validators.is_empty() { + let validator_keys: Vec<_> = self + .external_validators + .clone() + .into_iter() + .map(|(account, _balance)| { + let authority_keys = + get_authority_keys_from_seed(&account.to_string(), self.keystore.as_ref()); + ( + account.clone(), + account, + crate::SessionKeys { + babe: authority_keys.babe.clone(), + grandpa: authority_keys.grandpa.clone(), + para_validator: authority_keys.para_validator.clone(), + para_assignment: authority_keys.para_assignment.clone(), + authority_discovery: authority_keys.authority_discovery.clone(), + beefy: authority_keys.beefy.clone(), + nimbus: authority_keys.nimbus.clone(), + }, + ) + }) + .collect(); + keys.extend(validator_keys) + } + if !self.collators.is_empty() { // We set invulnerables in pallet_invulnerables let invulnerables: Vec = self @@ -674,6 +710,11 @@ impl ExtBuilder { .iter() .map(|(account, _)| account.clone()) .collect(), + external_validators: self + .external_validators + .iter() + .map(|(account, _)| account.clone()) + .collect(), } .assimilate_storage(&mut t) .unwrap(); diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs index b4d4ae11e..4deb7891b 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs @@ -713,6 +713,11 @@ fn external_validators_rewards_sends_message_on_era_end() { (AccountId::from(ALICE), 210_000 * UNIT), (AccountId::from(BOB), 100_000 * UNIT), ]) + .with_validators(vec![]) + .with_external_validators(vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ]) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here().into(); @@ -829,18 +834,13 @@ fn external_validators_rewards_merkle_proofs() { vec![AccountId::from(CHARLIE), AccountId::from(DAVE)] ); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 0 - ); - // Reward all validators in era 1 crate::RewardValidators::reward_backing(vec![ValidatorIndex(0)]); crate::RewardValidators::reward_backing(vec![ValidatorIndex(1)]); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 1 + assert_eq!( + pallet_external_validators_rewards::RewardPointsForEra::::iter().count(), + 1 ); let (_era_index, era_rewards) = @@ -1048,8 +1048,6 @@ fn external_validators_whitelisted_never_rewarded() { #[test] fn external_validators_rewards_test_command_integrity() { - use {crate::ValidatorIndex, runtime_parachains::inclusion::RewardValidators}; - ExtBuilder::default() .with_balances(vec![ (AccountId::from(ALICE), 210_000 * UNIT), @@ -1139,18 +1137,10 @@ fn external_validators_rewards_test_command_integrity() { vec![AccountId::from(CHARLIE), AccountId::from(DAVE)] ); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 0 - ); - - // Reward Alice and Bob in era 1 - crate::RewardValidators::reward_backing(vec![ValidatorIndex(0)]); - crate::RewardValidators::reward_backing(vec![ValidatorIndex(1)]); - - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 1 + // Validators are automatically rewarded. + assert_eq!( + pallet_external_validators_rewards::RewardPointsForEra::::iter().count(), + 1 ); let expected_inflation = @@ -1180,10 +1170,16 @@ fn external_validators_rewards_test_command_integrity() { .count(); let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + + let blocks_per_session: u128 = Babe::current_epoch().duration.into(); + let points_per_block = 20; + let expected_total_points = + (sessions_per_era as u128) * blocks_per_session * points_per_block; + let expected_rewards_command = Command::ReportRewards { external_idx: 1u64, era_index: 1u32, - total_points: 40u128, + total_points: expected_total_points, tokens_inflated: expected_inflation, rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, token_id, @@ -1209,6 +1205,15 @@ fn external_validators_rewards_are_minted_in_sovereign_account() { (AccountId::from(ALICE), 210_000 * UNIT), (AccountId::from(BOB), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs index 43fc94f28..790308ae9 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Tanssi. If not, see -use crate::tests::common::{mock_snowbridge_message_proof, ExtBuilder}; +use crate::tests::common::{mock_snowbridge_message_proof, ExtBuilder, ALICE, BOB, UNIT}; use crate::{AccountId, EthereumInboundQueue, ExternalValidators, Runtime}; use alloy_sol_types::SolEvent; use frame_system::pallet_prelude::OriginFor; @@ -33,7 +33,16 @@ use tp_bridge::symbiotic_message_processor::{ #[test] fn test_inbound_queue_message_passing() { - ExtBuilder::default().build().execute_with(|| { + ExtBuilder::default() + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ).build().execute_with(|| { let current_nonce = 1; snowbridge_pallet_system::Channels::::set(PRIMARY_GOVERNANCE_CHANNEL, Some(Channel { @@ -59,8 +68,6 @@ fn test_inbound_queue_message_passing() { proof: dummy_proof.clone(), }), Err(DispatchError::Other("No handler for message found"))); - assert_eq!(ExternalValidators::validators(), ExternalValidators::whitelisted_validators()); - let payload_validators = vec![ AccountKeyring::Charlie.to_account_id(), AccountKeyring::Ferdie.to_account_id(), @@ -91,7 +98,6 @@ fn test_inbound_queue_message_passing() { proof: dummy_proof.clone(), }), Ok(())); - let expected_validators = [ExternalValidators::whitelisted_validators(), payload_validators].concat(); assert_eq!(ExternalValidators::validators(), expected_validators); }); diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs index fa920191a..3298bc4b1 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs @@ -407,6 +407,11 @@ fn test_slashes_are_sent_to_ethereum() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators(vec![]) + .with_external_validators(vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ]) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here().into(); @@ -422,10 +427,6 @@ fn test_slashes_are_sent_to_ethereum() { )); run_to_block(2); - assert_ok!(ExternalValidators::remove_whitelisted( - RuntimeOrigin::root(), - AccountId::from(ALICE) - )); inject_babe_slash(&AccountId::from(ALICE).to_string()); @@ -552,6 +553,15 @@ fn test_slashes_are_sent_to_ethereum_accumulatedly() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() @@ -683,6 +693,15 @@ fn test_slashes_are_sent_to_ethereum_accumulate_until_next_era() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() diff --git a/chains/orchestrator-relays/runtime/dancelight/src/weights/mod.rs b/chains/orchestrator-relays/runtime/dancelight/src/weights/mod.rs index 7cf05dadf..dfd483e1e 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/weights/mod.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/weights/mod.rs @@ -18,7 +18,9 @@ pub mod frame_system; pub mod pallet_asset_rate; pub mod pallet_author_noting; pub mod pallet_balances; +pub mod pallet_beefy_mmr; pub mod pallet_collator_assignment; +pub mod pallet_configuration; pub mod pallet_conviction_voting; pub mod pallet_data_preservers; pub mod pallet_external_validator_slashes; @@ -27,6 +29,8 @@ pub mod pallet_external_validators_rewards; pub mod pallet_identity; pub mod pallet_invulnerables; pub mod pallet_message_queue; +pub mod pallet_mmr; +pub mod pallet_multiblock_migrations; pub mod pallet_multisig; pub mod pallet_parameters; pub mod pallet_pooled_staking; diff --git a/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_beefy_mmr.rs b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_beefy_mmr.rs new file mode 100644 index 000000000..292af5427 --- /dev/null +++ b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_beefy_mmr.rs @@ -0,0 +1,92 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see + + +//! Autogenerated weights for pallet_beefy_mmr +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 +//! DATE: 2025-02-07, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `pop-os`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dancelight-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/tanssi-relay +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_beefy_mmr +// --extrinsic +// * +// --chain=dancelight-dev +// --steps +// 2 +// --repeat +// 2 +// --template=benchmarking/frame-weight-runtime-template.hbs +// --json-file +// raw.json +// --output +// tmp/dancelight_weights/pallet_beefy_mmr.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for pallet_beefy_mmr using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_beefy_mmr::WeightInfo for SubstrateWeight { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn extract_validation_context() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 7_643_000 picoseconds. + Weight::from_parts(8_243_000, 3509) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Mmr::Nodes` (r:1 w:0) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn read_peak() -> Weight { + // Proof Size summary in bytes: + // Measured: `254` + // Estimated: `3505` + // Minimum execution time: 5_980_000 picoseconds. + Weight::from_parts(6_080_000, 3505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Mmr::RootHash` (r:1 w:0) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:0) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 512]`. + fn n_items_proof_is_non_canonical(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `246` + // Estimated: `1517` + // Minimum execution time: 15_086_000 picoseconds. + Weight::from_parts(12_589_666, 1517) + // Standard Error: 42_062 + .saturating_add(Weight::from_parts(1_281_166, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } +} \ No newline at end of file diff --git a/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_configuration.rs b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_configuration.rs new file mode 100644 index 000000000..2d44513e7 --- /dev/null +++ b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_configuration.rs @@ -0,0 +1,74 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see + + +//! Autogenerated weights for pallet_configuration +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 +//! DATE: 2025-02-10, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `pop-os`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dancelight-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/tanssi-relay +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_configuration +// --extrinsic +// * +// --chain=dancelight-dev +// --steps +// 2 +// --repeat +// 2 +// --template=benchmarking/frame-weight-runtime-template.hbs +// --json-file +// raw.json +// --output +// tmp/dancelight_weights/pallet_configuration.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for pallet_configuration using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_configuration::WeightInfo for SubstrateWeight { + /// Storage: `CollatorConfiguration::PendingConfigs` (r:1 w:1) + /// Proof: `CollatorConfiguration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CollatorConfiguration::ActiveConfig` (r:1 w:0) + /// Proof: `CollatorConfiguration::ActiveConfig` (`max_values`: Some(1), `max_size`: Some(52), added: 547, mode: `MaxEncodedLen`) + /// Storage: `CollatorConfiguration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `CollatorConfiguration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_u32() -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `2368` + // Minimum execution time: 19_433_000 picoseconds. + Weight::from_parts(22_416_000, 2368) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} \ No newline at end of file diff --git a/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_mmr.rs b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_mmr.rs new file mode 100644 index 000000000..854fe08ea --- /dev/null +++ b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_mmr.rs @@ -0,0 +1,88 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see + + +//! Autogenerated weights for pallet_mmr +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 +//! DATE: 2025-02-07, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `pop-os`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dancelight-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/tanssi-relay +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_mmr +// --extrinsic +// * +// --chain=dancelight-dev +// --steps +// 2 +// --repeat +// 2 +// --template=benchmarking/frame-weight-runtime-template.hbs +// --json-file +// raw.json +// --output +// tmp/dancelight_weights/pallet_mmr.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for pallet_mmr using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_mmr::WeightInfo for SubstrateWeight { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Parachains` (r:1 w:0) + /// Proof: `Paras::Parachains` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OutboundMessageCommitmentRecorder::RecordedCommitment` (r:1 w:0) + /// Proof: `OutboundMessageCommitmentRecorder::RecordedCommitment` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `Mmr::Nodes` (r:8 w:4) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Mmr::UseLocalStorage` (r:1 w:0) + /// Proof: `Mmr::UseLocalStorage` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `347 + x * (39 ±0)` + // Estimated: `1833 + x * (39 ±0)` + // Minimum execution time: 26_038_000 picoseconds. + Weight::from_parts(27_790_287, 1833) + // Standard Error: 2_013 + .saturating_add(Weight::from_parts(79_212, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } +} \ No newline at end of file diff --git a/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_multiblock_migrations.rs b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_multiblock_migrations.rs new file mode 100644 index 000000000..91a93181d --- /dev/null +++ b/chains/orchestrator-relays/runtime/dancelight/src/weights/pallet_multiblock_migrations.rs @@ -0,0 +1,200 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see + + +//! Autogenerated weights for pallet_multiblock_migrations +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 +//! DATE: 2025-02-07, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `pop-os`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dancelight-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/tanssi-relay +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_multiblock_migrations +// --extrinsic +// * +// --chain=dancelight-dev +// --steps +// 2 +// --repeat +// 2 +// --template=benchmarking/frame-weight-runtime-template.hbs +// --json-file +// raw.json +// --output +// tmp/dancelight_weights/pallet_multiblock_migrations.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for pallet_multiblock_migrations using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_multiblock_migrations::WeightInfo for SubstrateWeight { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `67035` + // Minimum execution time: 8_463_000 picoseconds. + Weight::from_parts(10_641_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `67035` + // Minimum execution time: 2_015_000 picoseconds. + Weight::from_parts(3_123_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `96` + // Estimated: `3561` + // Minimum execution time: 6_502_000 picoseconds. + Weight::from_parts(7_241_000, 3561) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `154` + // Estimated: `3731` + // Minimum execution time: 11_145_000 picoseconds. + Weight::from_parts(11_802_000, 3731) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `3731` + // Minimum execution time: 10_505_000 picoseconds. + Weight::from_parts(13_921_000, 3731) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `3731` + // Minimum execution time: 12_461_000 picoseconds. + Weight::from_parts(15_000_000, 3731) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `3731` + // Minimum execution time: 12_912_000 picoseconds. + Weight::from_parts(15_853_000, 3731) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 185_000 picoseconds. + Weight::from_parts(194_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_978_000 picoseconds. + Weight::from_parts(5_761_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_328_000 picoseconds. + Weight::from_parts(5_973_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `67035` + // Minimum execution time: 6_122_000 picoseconds. + Weight::from_parts(9_781_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1034 + n * (269 ±0)` + // Estimated: `3731 + n * (2730 ±0)` + // Minimum execution time: 21_830_000 picoseconds. + Weight::from_parts(26_025_000, 3731) + // Standard Error: 347_090 + .saturating_add(Weight::from_parts(1_540_582, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2730).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/pallets/external-validators-rewards/src/lib.rs b/pallets/external-validators-rewards/src/lib.rs index 7952f83b7..c41baeb42 100644 --- a/pallets/external-validators-rewards/src/lib.rs +++ b/pallets/external-validators-rewards/src/lib.rs @@ -43,7 +43,7 @@ use { snowbridge_core::{ChannelId, TokenId}, snowbridge_outbound_queue_merkle_tree::{merkle_proof, merkle_root, verify_proof, MerkleProof}, sp_core::H256, - sp_runtime::traits::{Hash, MaybeEquivalence}, + sp_runtime::traits::{Hash, MaybeEquivalence, Zero}, sp_staking::SessionIndex, sp_std::collections::btree_set::BTreeSet, sp_std::vec, @@ -268,73 +268,92 @@ pub mod pallet { impl tp_traits::OnEraEnd for Pallet { fn on_era_end(era_index: EraIndex) { + // Will send a ReportRewards message to Ethereum unless: + // - the reward token is misconfigured + // - the tokens inflation is 0 (misconfigured inflation) + // - the total points is 0 (no rewards to distribute) + // - it fails to mint the tokens in the Ethereum Sovereign Account + // - the generated message doesn't pass validation + let token_location = T::TokenLocationReanchored::get(); let token_id = T::TokenIdFromLocation::convert_back(&token_location); - if let Some(token_id) = token_id { - if let Some(utils) = Self::generate_era_rewards_utils(era_index, None) { - let tokens_inflated = T::EraInflationProvider::get(); - - let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get(); - if let Err(err) = - T::Currency::mint_into(ðereum_sovereign_account, tokens_inflated.into()) - { - log::error!(target: "ext_validators_rewards", "Failed to mint inflation into Ethereum Soverein Account: {err:?}"); - log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute"); - return; - } + let Some(token_id) = token_id else { + log::error!(target: "ext_validators_rewards", "no token id found for location {:?}", token_location); + return; + }; - let command = Command::ReportRewards { - external_idx: T::ExternalIndexProvider::get_external_index(), - era_index, - total_points: utils.total_points, - tokens_inflated, - rewards_merkle_root: utils.rewards_merkle_root, - token_id, - }; - - let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL; - - let outbound_message = Message { - id: None, - channel_id, - command: command.clone(), - }; - - // Validate and deliver the message - match T::ValidateMessage::validate(&outbound_message) { - Ok((ticket, _fee)) => { - let message_id = ticket.message_id(); - if let Err(err) = T::OutboundQueue::deliver(ticket) { - log::error!(target: "ext_validators_rewards", "OutboundQueue delivery of message failed. {err:?}"); - } else { - Self::deposit_event(Event::RewardsMessageSent { - message_id, - rewards_command: command, - }); - } - } - Err(err) => { - log::error!(target: "ext_validators_rewards", "OutboundQueue validation of message failed. {err:?}"); - } - } + let Some(utils) = Self::generate_era_rewards_utils(era_index, None) else { + // Unreachable, this should never happen as we are sending + // None as the second param in Self::generate_era_rewards_utils. + log::error!( + target: "ext_validators_rewards", + "Outbound message not sent for era {:?}!", + era_index + ); + return; + }; - frame_system::Pallet::::register_extra_weight_unchecked( - T::WeightInfo::on_era_end(), - DispatchClass::Mandatory, - ); - } else { - // Unreachable, this should never happen as we are sending - // None as the second param in Self::generate_era_rewards_utils. - log::error!( - target: "ext_validators_rewards", - "Outbound message not sent for era {:?}!", - era_index - ); + let tokens_inflated = T::EraInflationProvider::get(); + + if tokens_inflated.is_zero() { + log::error!(target: "ext_validators_rewards", "Not sending message because tokens_inflated is 0"); + return; + } + + if utils.total_points.is_zero() { + log::error!(target: "ext_validators_rewards", "Not sending message because total_points is 0"); + return; + } + + let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get(); + if let Err(err) = + T::Currency::mint_into(ðereum_sovereign_account, tokens_inflated.into()) + { + log::error!(target: "ext_validators_rewards", "Failed to mint inflation into Ethereum Soverein Account: {err:?}"); + log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute"); + return; + } + + let command = Command::ReportRewards { + external_idx: T::ExternalIndexProvider::get_external_index(), + era_index, + total_points: utils.total_points, + tokens_inflated, + rewards_merkle_root: utils.rewards_merkle_root, + token_id, + }; + + let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL; + + let outbound_message = Message { + id: None, + channel_id, + command: command.clone(), + }; + + // Validate and deliver the message + match T::ValidateMessage::validate(&outbound_message) { + Ok((ticket, _fee)) => { + let message_id = ticket.message_id(); + if let Err(err) = T::OutboundQueue::deliver(ticket) { + log::error!(target: "ext_validators_rewards", "OutboundQueue delivery of message failed. {err:?}"); + } else { + Self::deposit_event(Event::RewardsMessageSent { + message_id, + rewards_command: command, + }); + } + } + Err(err) => { + log::error!(target: "ext_validators_rewards", "OutboundQueue validation of message failed. {err:?}"); } - } else { - log::debug!(target: "ext_validators_rewards", "no token id found for location {:?}", token_location); } + + frame_system::Pallet::::register_extra_weight_unchecked( + T::WeightInfo::on_era_end(), + DispatchClass::Mandatory, + ); } } } diff --git a/pallets/external-validators-rewards/src/mock.rs b/pallets/external-validators-rewards/src/mock.rs index 174ce8284..6aeefe9e6 100644 --- a/pallets/external-validators-rewards/src/mock.rs +++ b/pallets/external-validators-rewards/src/mock.rs @@ -17,7 +17,7 @@ use { crate as pallet_external_validators_rewards, frame_support::{ parameter_types, - traits::{ConstU128, ConstU32, ConstU64}, + traits::{ConstU32, ConstU64}, }, pallet_balances::AccountData, snowbridge_core::{ @@ -156,6 +156,7 @@ parameter_types! { pub const RewardsEthereumSovereignAccount: u64 = 0xffffffffffffffff; pub RewardTokenLocation: Location = Location::here(); + pub EraInflationProvider: u128 = Mock::mock().era_inflation.unwrap_or(42); } impl pallet_external_validators_rewards::Config for Test { @@ -164,7 +165,7 @@ impl pallet_external_validators_rewards::Config for Test { type HistoryDepth = ConstU32<10>; type BackingPoints = ConstU32<20>; type DisputeStatementPoints = ConstU32<20>; - type EraInflationProvider = ConstU128<42>; + type EraInflationProvider = EraInflationProvider; type ExternalIndexProvider = TimestampProvider; type GetWhitelistedValidators = (); type Hashing = Keccak256; @@ -191,6 +192,7 @@ pub mod mock_data { #[derive(Clone, Default, Encode, Decode, sp_core::RuntimeDebug, scale_info::TypeInfo)] pub struct Mocks { pub active_era: Option, + pub era_inflation: Option, } #[pallet::config] diff --git a/pallets/external-validators-rewards/src/tests.rs b/pallets/external-validators-rewards/src/tests.rs index 77e367d99..d97639aab 100644 --- a/pallets/external-validators-rewards/src/tests.rs +++ b/pallets/external-validators-rewards/src/tests.rs @@ -16,7 +16,6 @@ use { crate::{self as pallet_external_validators_rewards, mock::*}, - frame_support::traits::Get, sp_core::H256, sp_std::collections::btree_map::BTreeMap, tp_bridge::Command, @@ -175,3 +174,100 @@ fn test_on_era_end_without_proper_token() { ); }) } + +#[test] +fn test_on_era_end_with_zero_inflation() { + new_test_ext().execute_with(|| { + run_to_block(1); + + Mock::mutate(|mock| { + mock.active_era = Some(ActiveEraInfo { + index: 1, + start: None, + }); + mock.era_inflation = Some(0); + }); + let points = vec![10u32, 30u32, 50u32]; + let total_points: u32 = points.iter().cloned().sum(); + let accounts = vec![1u64, 3u64, 5u64]; + let accounts_points: Vec<(u64, crate::RewardPoints)> = accounts + .iter() + .cloned() + .zip(points.iter().cloned()) + .collect(); + ExternalValidatorsRewards::reward_by_ids(accounts_points); + ExternalValidatorsRewards::on_era_end(1); + + let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + let expected_command = Command::ReportRewards { + external_idx: 31000u64, + era_index: 1u32, + total_points: total_points as u128, + tokens_inflated: + ::EraInflationProvider::get(), // test inflation value used in mock + rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, + token_id: H256::repeat_byte(0x01), + }; + + let events = System::events(); + let expected_not_thrown_event = + RuntimeEvent::ExternalValidatorsRewards(crate::Event::RewardsMessageSent { + message_id: Default::default(), + rewards_command: expected_command, + }); + assert!( + !events + .iter() + .any(|record| record.event == expected_not_thrown_event), + "event should not have been thrown", + ); + }) +} + +#[test] +fn test_on_era_end_with_zero_points() { + new_test_ext().execute_with(|| { + run_to_block(1); + + Mock::mutate(|mock| { + mock.active_era = Some(ActiveEraInfo { + index: 1, + start: None, + }); + }); + let points = vec![0u32, 0u32, 0u32]; + let total_points: u32 = points.iter().cloned().sum(); + let accounts = vec![1u64, 3u64, 5u64]; + let accounts_points: Vec<(u64, crate::RewardPoints)> = accounts + .iter() + .cloned() + .zip(points.iter().cloned()) + .collect(); + ExternalValidatorsRewards::reward_by_ids(accounts_points); + ExternalValidatorsRewards::on_era_end(1); + + let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + let expected_command = Command::ReportRewards { + external_idx: 31000u64, + era_index: 1u32, + total_points: total_points as u128, + tokens_inflated: + ::EraInflationProvider::get(), // test inflation value used in mock + rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, + token_id: H256::repeat_byte(0x01), + }; + + let events = System::events(); + let expected_not_thrown_event = + RuntimeEvent::ExternalValidatorsRewards(crate::Event::RewardsMessageSent { + message_id: Default::default(), + rewards_command: expected_command, + }); + assert!( + !events + .iter() + .any(|record| record.event == expected_not_thrown_event), + "event should not have been thrown", + ); + }) +} diff --git a/pallets/external-validators/src/lib.rs b/pallets/external-validators/src/lib.rs index 5ad7e59c3..541a722b0 100644 --- a/pallets/external-validators/src/lib.rs +++ b/pallets/external-validators/src/lib.rs @@ -214,6 +214,7 @@ pub mod pallet { pub struct GenesisConfig { pub skip_external_validators: bool, pub whitelisted_validators: Vec, + pub external_validators: Vec, } #[pallet::genesis_build] @@ -236,10 +237,16 @@ pub mod pallet { ) .expect("genesis validators are more than T::MaxWhitelistedValidators"); + let bounded_external_validators = BoundedVec::<_, T::MaxExternalValidators>::try_from( + self.external_validators.clone(), + ) + .expect("genesis external validators are more than T::MaxExternalValidators"); + >::put(self.skip_external_validators); >::put(&bounded_validators); >::put(&bounded_validators); >::put(&bounded_validators); + >::put(&bounded_external_validators); } } diff --git a/pallets/external-validators/src/mock.rs b/pallets/external-validators/src/mock.rs index c3eea772b..39b3622fc 100644 --- a/pallets/external-validators/src/mock.rs +++ b/pallets/external-validators/src/mock.rs @@ -298,6 +298,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_external_validators::GenesisConfig:: { skip_external_validators: false, whitelisted_validators, + ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ca6869db..f444270bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -179,6 +179,9 @@ importers: solc: specifier: 0.8.21 version: 0.8.21(debug@4.3.7) + toml: + specifier: ^3.0.0 + version: 3.0.0 tsx: specifier: '*' version: 4.19.2 diff --git a/test/moonwall.config.json b/test/moonwall.config.json index 35fdaecb1..88ece5371 100644 --- a/test/moonwall.config.json +++ b/test/moonwall.config.json @@ -192,7 +192,7 @@ "testFileDir": ["suites/zombie_tanssi"], "runScripts": [ "build-spec-flashbox.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/flashbox-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/template-container-2000.json", "compile-wasm.ts compile -b ../target/release/container-chain-frontier-node -o wasm -c specs/template-container-2001.json" @@ -251,7 +251,7 @@ "testFileDir": ["suites/zombie_tanssi"], "runScripts": [ "build-spec.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/template-container-2000.json", "compile-wasm.ts compile -b ../target/release/container-chain-frontier-node -o wasm -c specs/template-container-2001.json" @@ -309,7 +309,7 @@ "testFileDir": ["suites/zombie_tanssi_keep_db"], "runScripts": [ "build-spec-single-container.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/single-container-template-container-2000.json" ], @@ -346,7 +346,7 @@ "testFileDir": ["suites/zombie_tanssi_metrics"], "runScripts": [ "build-spec-single-container.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/single-container-template-container-2000.json" ], @@ -384,7 +384,7 @@ "testFileDir": ["suites/zombie_tanssi_one_node"], "runScripts": [ "build-spec-one-node.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/one-node-tanssi-1000.json" ], "foundation": { @@ -416,7 +416,7 @@ "testFileDir": ["suites/zombie_tanssi_parathreads"], "runScripts": [ "build-spec-parathreads.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/parathreads-tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/parathreads-template-container-2000.json", "compile-wasm.ts compile -b ../target/release/container-chain-frontier-node -o wasm -c specs/parathreads-template-container-2001.json" @@ -469,7 +469,7 @@ "testFileDir": ["suites/zombie_tanssi_rotation"], "runScripts": [ "build-spec.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/template-container-2000.json", "compile-wasm.ts compile -b ../target/release/container-chain-frontier-node -o wasm -c specs/template-container-2001.json" @@ -522,7 +522,7 @@ "testFileDir": ["suites/zombie_tanssi_warp_sync"], "runScripts": [ "build-spec-single-container.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/single-container-template-container-2000.json" ], @@ -557,7 +557,7 @@ { "name": "zombie_dancebox_upgrade", "testFileDir": ["suites/zombie_dancebox_upgrade"], - "runScripts": ["download-polkadot.sh"], + "runScripts": ["downloadPolkadot.ts"], "timeout": 600000, "foundation": { "rtUpgradePath": "../target/release/wbuild/dancebox-runtime/dancebox_runtime.compact.compressed.wasm", @@ -574,7 +574,7 @@ "runScripts": [ "download-latest-rt-binaries.sh", "build-spec-single-container.sh tmp container-chain-simple-node flashbox-local", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b tmp/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b tmp/container-chain-simple-node -o wasm -c specs/single-container-template-container-2000.json" ], @@ -638,7 +638,7 @@ "runScripts": [ "download-latest-rt-binaries.sh", "build-spec-single-container.sh tmp container-chain-simple-node flashbox-local", - "download-polkadot.sh", + "downloadPolkadot.ts", "download-latest-binaries.sh ../target/release", "compile-wasm.ts compile -b tmp/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b tmp/container-chain-simple-node -o wasm -c specs/single-container-template-container-2000.json" @@ -710,7 +710,7 @@ "runScripts": [ "download-latest-rt-binaries.sh", "build-spec-single-container.sh tmp container-chain-frontier-node flashbox-local", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b tmp/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b tmp/container-chain-frontier-node -o wasm -c specs/single-container-template-container-2000.json" ], @@ -750,7 +750,7 @@ "runScripts": [ "download-latest-rt-binaries.sh", "build-spec-single-container.sh tmp container-chain-frontier-node flashbox-local", - "download-polkadot.sh", + "downloadPolkadot.ts", "download-latest-binaries.sh ../target/release", "compile-wasm.ts compile -b tmp/tanssi-node -o wasm -c specs/single-container-tanssi-1000.json", "compile-wasm.ts compile -b tmp/container-chain-frontier-node -o wasm -c specs/single-container-template-container-2000.json" @@ -872,7 +872,7 @@ "testFileDir": ["suites/zombie_data_preservers"], "runScripts": [ "build-spec-data-preservers.sh", - "download-polkadot.sh", + "downloadPolkadot.ts", "compile-wasm.ts compile -b ../target/release/tanssi-node -o wasm -c specs/data-preservers-dancebox-1000.json", "compile-wasm.ts compile -b ../target/release/container-chain-simple-node -o wasm -c specs/data-preservers-container-2000.json", "compile-wasm.ts compile -b ../target/release/container-chain-frontier-node -o wasm -c specs/data-preservers-container-2001.json" diff --git a/test/package.json b/test/package.json index 1bad3952b..e746110e4 100644 --- a/test/package.json +++ b/test/package.json @@ -59,6 +59,7 @@ "tsx": "*", "typescript": "*", "viem": "2.22.21", + "toml": "^3.0.0", "vitest": "2.1.5", "web3": "4.15.0", "web3-providers-ws": "4.0.8", diff --git a/test/polkadotReleaseMapping.json b/test/polkadotReleaseMapping.json new file mode 100644 index 000000000..7da21e745 --- /dev/null +++ b/test/polkadotReleaseMapping.json @@ -0,0 +1,7 @@ +{ + "stable2409": { + "polkadot": "599cb6b8a0f67098717315c6db33e28983873e6c94a4272c9d0a03dd06b70428", + "polkadot-prepare-worker": "4dc5964da9052faee01f0d727fda08ab573989ac6c81f597d21028e76ae22f9c", + "polkadot-execute-worker": "8932f0b07323a497470de2c7d8b9b7583af27de3836518fbf62047a68bc788f9" + } +} diff --git a/test/scripts/download-polkadot.sh b/test/scripts/download-polkadot.sh index 93a326084..598ac29f2 100755 --- a/test/scripts/download-polkadot.sh +++ b/test/scripts/download-polkadot.sh @@ -25,22 +25,7 @@ delete_if_not_binary tmp/polkadot-execute-worker delete_if_not_binary tmp/polkadot-prepare-worker if [[ -f tmp/polkadot && -f tmp/polkadot-execute-worker && -f tmp/polkadot-prepare-worker ]]; then - POLKADOT_VERSION=$(tmp/polkadot --version) - if [[ $POLKADOT_VERSION == *$polkadot_release* ]]; then - exit 0 - else - echo "Updating polkadot binary from $POLKADOT_VERSION to $polkadot_release" - - pnpm moonwall download polkadot $polkadot_release tmp - chmod +x tmp/polkadot - - pnpm moonwall download polkadot-execute-worker $polkadot_release tmp - chmod +x tmp/polkadot-execute-worker - - pnpm moonwall download polkadot-prepare-worker $polkadot_release tmp - chmod +x tmp/polkadot-prepare-worker - - fi + echo "Polkadot binary already found, skipping download ..." else echo "Polkadot binary not found, downloading $polkadot_release" pnpm moonwall download polkadot $polkadot_release tmp diff --git a/test/scripts/downloadPolkadot.ts b/test/scripts/downloadPolkadot.ts new file mode 100644 index 000000000..a0823b2c5 --- /dev/null +++ b/test/scripts/downloadPolkadot.ts @@ -0,0 +1,147 @@ +/* eslint-disable */ +import jsonFile from "../polkadotReleaseMapping.json" with { type: "json" }; +import fs from "node:fs/promises"; +import fsSync from "node:fs"; +import assert from "node:assert"; +import { parse } from "toml"; +import path from "node:path"; +import { execSync } from "node:child_process"; +import { createHash } from "node:crypto"; + +const CONFIG = { + FOLDER_NAME: "tmp", + BINARIES: ["polkadot", "polkadot-execute-worker", "polkadot-prepare-worker"] as const, + CARGO_PATH: "../Cargo.toml", +} as const; + +async function main() { + const polkadotVersionMappings: PolkadotVersionMapping = jsonFile; + const fileContents = await fs.readFile(CONFIG.CARGO_PATH, "utf-8"); + const cargoToml = parse(fileContents) as CargoToml; + const stableVersion = findPolkadotStableVersion(cargoToml.workspace.dependencies); + console.log(`🔎 Found polkadot-sdk version: ${stableVersion}`); + + for (const binName of CONFIG.BINARIES) { + const pathName = path.join(CONFIG.FOLDER_NAME, binName); + if (fsSync.existsSync(pathName)) { + const existingChecksum = getSha256(pathName); + console.log(`✏️ File already exists: ${mini(existingChecksum)}`); + + const savedChecksum = polkadotVersionMappings[stableVersion]?.[binName]; + + if (!savedChecksum || savedChecksum !== existingChecksum) { + if (!savedChecksum) { + console.log(`⚠️ Saved checksum not found for ${binName}:${stableVersion}`); + } else { + console.log(`⚠️ File mismatch ${mini(existingChecksum)} vs ${mini(savedChecksum)}, downloading...`); + } + execSync(`pnpm moonwall download -d ${binName} ${stableVersion} ${CONFIG.FOLDER_NAME}`, { + stdio: "inherit", + }); + const sha256 = getSha256(pathName); + polkadotVersionMappings[stableVersion] = { + ...polkadotVersionMappings[stableVersion], + [binName]: sha256, + }; + await fs.writeFile("polkadotReleaseMapping.json", JSON.stringify(polkadotVersionMappings, null, 2)); + } else { + console.log(`✅ Binary ${pathName} matches saved version`); + } + } else { + // New File flow + console.log("📥️ File does not exist, downloading..."); + execSync(`pnpm moonwall download ${binName} ${stableVersion} ${CONFIG.FOLDER_NAME}`, { stdio: "inherit" }); + const sha256 = getSha256(pathName); + console.log(`💾 Downloaded file: ${mini(sha256)}`); + polkadotVersionMappings[stableVersion] = { + ...polkadotVersionMappings[stableVersion], + [binName]: sha256, + }; + await fs.writeFile("polkadotReleaseMapping.json", JSON.stringify(polkadotVersionMappings, null, 2)); + console.log("✅ Saved to version mapping "); + } + } +} + +main() + .then(() => console.log(`🎉 Finished verifying binaries: [${CONFIG.BINARIES.join(", ")}]`)) + .catch((err: unknown) => { + console.error("❌ Error:", err); + process.exit(1); + }); +/** + * Interfaces + **/ + +interface PolkadotVersionMapping { + [key: `stable${number}-${number}` | `stable${number}`]: DownloadHashes; +} +interface CargoToml { + workspace: { + dependencies: Record; + }; +} + +interface DownloadHashes { + polkadot: string; + "polkadot-execute-worker": string; + "polkadot-prepare-worker": string; +} + +/** + * Functions + **/ +function extractStableVersion(branch: string): string | null { + const match = branch.match(/stable(\d+)/); + return match ? `stable${match[1]}` : null; +} + +function findPolkadotStableVersion(dependencies: Record): string { + const polkadotDeps = Object.entries(dependencies).filter( + ([_, config]) => typeof config === "object" && config.git === "https://github.com/moondance-labs/polkadot-sdk" + ); + + let stableVersions: Array | Set = new Set( + polkadotDeps + .map(([_, config]) => extractStableVersion(config.branch)) + .filter((version): version is string => version !== null) + ); + + if (stableVersions.size === 0) { + throw new Error("No stable version found in polkadot-sdk dependencies"); + } + + if (stableVersions.size > 1) { + stableVersions = Array.from(stableVersions).sort((a, b) => { + // Extract numbers and compare + const aMatch = a.match(/stable(\d+)(?:-(\d+))?/); + const bMatch = b.match(/stable(\d+)(?:-(\d+))?/); + + assert(aMatch, "this is already mapped, this should never happen"); + assert(bMatch, "this is already mapped, this should never happen"); + + const mainVersionDiff = Number.parseInt(bMatch[1]) - Number.parseInt(aMatch[1]); + if (mainVersionDiff !== 0) { + return mainVersionDiff; + } + + const aSubVersion = aMatch[2] ? Number.parseInt(aMatch[2]) : 0; + const bSubVersion = bMatch[2] ? Number.parseInt(bMatch[2]) : 0; + return bSubVersion - aSubVersion; + }); + console.error( + `⚠️ Multiple stable versions found: ${Array.from(stableVersions).join(", ")}. Choosing: ${stableVersions[0]}` + ); + } + + return Array.from(stableVersions)[0]; +} + +const getSha256 = (filePath: string) => { + const fileBuffer = fsSync.readFileSync(filePath); + const hashSum = createHash("sha256"); + hashSum.update(fileBuffer); + return hashSum.digest("hex"); +}; + +const mini = (hash: string) => `<${hash.slice(0, 4)}...${hash.slice(-4)}>`; diff --git a/test/suites/smoke-test-dancelight/test-babe.ts b/test/suites/smoke-test-dancelight/test-babe.ts index da446122f..e7922b5bb 100644 --- a/test/suites/smoke-test-dancelight/test-babe.ts +++ b/test/suites/smoke-test-dancelight/test-babe.ts @@ -155,7 +155,7 @@ describeSuite({ expect(sealLogs.length).to.eq(1); const sealLog = api.registry.createType( - "PolkadotPrimitivesV7ValidatorAppSignature", + "PolkadotPrimitivesV8ValidatorAppSignature", sealLogs[0].asSeal[1].toHex() ); diff --git a/test/suites/smoke-test-dancelight/test-validators-match-external-validators.ts b/test/suites/smoke-test-dancelight/test-validators-match-external-validators.ts index df2219746..a9d7db886 100644 --- a/test/suites/smoke-test-dancelight/test-validators-match-external-validators.ts +++ b/test/suites/smoke-test-dancelight/test-validators-match-external-validators.ts @@ -17,7 +17,7 @@ describeSuite({ id: "C01", title: "Validators should match external validators", - test: async (vitest) => { + test: async () => { // Find the last block in which the era changed const currentEra = await api.query.externalValidators.currentEra(); if (currentEra.isNone) { @@ -27,11 +27,8 @@ describeSuite({ let blockToCheck = (await api.query.babe.epochStart())[1].toNumber(); let apiBeforeLatestNewSession = await api.at(await api.rpc.chain.getBlockHash(blockToCheck - 1)); - while ( - currentEra.unwrap().toBigInt() === - (await apiBeforeLatestNewSession.query.externalValidators.currentEra()).unwrap().toBigInt() - ) { - blockToCheck = (await apiBeforeLatestNewSession.query.babe.epochStart())[1].toNumber(); + while (currentEra === (await apiBeforeLatestNewSession.query.externalValidators.currentEra())) { + blockToCheck = (await apiBeforeLatestNewSession.query.babe.epochStart()).toJSON()[1]; apiBeforeLatestNewSession = await api.at(await api.rpc.chain.getBlockHash(blockToCheck - 1)); } diff --git a/test/suites/zombie_dancebox_upgrade/test_zombie_dancebox_upgrade.ts b/test/suites/zombie_dancebox_upgrade/test_zombie_dancebox_upgrade.ts index 459993697..dc21f25d7 100644 --- a/test/suites/zombie_dancebox_upgrade/test_zombie_dancebox_upgrade.ts +++ b/test/suites/zombie_dancebox_upgrade/test_zombie_dancebox_upgrade.ts @@ -1,5 +1,6 @@ +import "@tanssi/api-augment"; import { MoonwallContext, beforeAll, describeSuite, expect } from "@moonwall/cli"; -import type { KeyringPair } from "@moonwall/util"; +import { generateKeyringPair, type KeyringPair } from "@moonwall/util"; import { type ApiPromise, Keyring } from "@polkadot/api"; import fs from "node:fs"; @@ -41,7 +42,7 @@ describeSuite({ id: "T02", title: "Chain can be upgraded", timeout: 600000, - test: async () => { + test: async ({ skip }) => { const blockNumberBefore = (await paraApi.rpc.chain.getBlock()).block.header.number.toNumber(); const currentCode = await paraApi.rpc.state.getStorage(":code"); const codeString = currentCode.toString(); @@ -52,15 +53,17 @@ describeSuite({ if (rtHex === codeString) { log("Runtime already upgraded, skipping test"); - return; + skip(); } log("Runtime not upgraded, proceeding with test"); + log("Current runtime spec version:", rtBefore); log(`Current runtime hash: ${rtHex.slice(0, 10)}...${rtHex.slice(-10)}`); log(`New runtime hash: ${codeString.slice(0, 10)}...${codeString.slice(-10)}`); await context.upgradeRuntime({ from: alice, logger: log }); await context.waitBlock(2); const rtafter = paraApi.consts.system.version.specVersion.toNumber(); + log("New runtime spec version:", rtafter); if (rtBefore === rtafter) { throw new Error("Runtime upgrade failed"); } @@ -69,5 +72,39 @@ describeSuite({ expect(blockNumberAfter, "Block number did not increase").to.be.greaterThan(blockNumberBefore); }, }); + + it({ + id: "T03", + title: "Can send balance transfers", + timeout: 600000, + test: async () => { + const randomAccount = generateKeyringPair("sr25519"); + + let tries = 0; + const balanceBefore = (await paraApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + + /// It might happen that by accident we hit a session change + /// A block in which a session change occurs cannot hold any tx + /// Chopsticks does not have the notion of tx pool either, so we need to retry + /// Therefore we just retry at most MAX_BALANCE_TRANSFER_TRIES + const MAX_BALANCE_TRANSFER_TRIES = 5; + while (tries < MAX_BALANCE_TRANSFER_TRIES) { + const txHash = await paraApi.tx.balances + .transferAllowDeath(randomAccount.address, 1_000_000_000) + .signAndSend(alice); + await context.waitBlock(1); + + const block = await paraApi.rpc.chain.getBlock(); + const includedTxHashes = block.block.extrinsics.map((x) => x.hash.toString()); + if (includedTxHashes.includes(txHash.toString())) { + break; + } + tries++; + } + + const balanceAfter = (await paraApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + expect(balanceBefore < balanceAfter).to.be.true; + }, + }); }, }); diff --git a/test/suites/zombie_dancelight_upgrade/test_zombie_dancelight_upgrade.ts b/test/suites/zombie_dancelight_upgrade/test_zombie_dancelight_upgrade.ts index 0899ae221..5fe81be27 100644 --- a/test/suites/zombie_dancelight_upgrade/test_zombie_dancelight_upgrade.ts +++ b/test/suites/zombie_dancelight_upgrade/test_zombie_dancelight_upgrade.ts @@ -1,5 +1,6 @@ +import "@tanssi/api-augment"; import { MoonwallContext, beforeAll, describeSuite, expect } from "@moonwall/cli"; -import type { KeyringPair } from "@moonwall/util"; +import { generateKeyringPair, type KeyringPair } from "@moonwall/util"; import { type ApiPromise, Keyring } from "@polkadot/api"; import fs from "node:fs"; @@ -36,7 +37,7 @@ describeSuite({ id: "T02", title: "Chain can be upgraded", timeout: 600000, - test: async () => { + test: async ({ skip }) => { const blockNumberBefore = (await relayApi.rpc.chain.getBlock()).block.header.number.toNumber(); const currentCode = await relayApi.rpc.state.getStorage(":code"); const codeString = currentCode.toString(); @@ -47,15 +48,17 @@ describeSuite({ if (rtHex === codeString) { log("Runtime already upgraded, skipping test"); - return; + skip(); } log("Runtime not upgraded, proceeding with test"); + log("Current runtime spec version:", rtBefore); log(`Current runtime hash: ${rtHex.slice(0, 10)}...${rtHex.slice(-10)}`); log(`New runtime hash: ${codeString.slice(0, 10)}...${codeString.slice(-10)}`); await context.upgradeRuntime({ from: alice, logger: log }); await context.waitBlock(2); const rtafter = relayApi.consts.system.version.specVersion.toNumber(); + log("New runtime spec version:", rtafter); if (rtBefore === rtafter) { throw new Error("Runtime upgrade failed"); } @@ -64,5 +67,39 @@ describeSuite({ expect(blockNumberAfter, "Block number did not increase").to.be.greaterThan(blockNumberBefore); }, }); + + it({ + id: "T03", + title: "Can send balance transfers", + timeout: 600000, + test: async () => { + const randomAccount = generateKeyringPair("sr25519"); + + let tries = 0; + const balanceBefore = (await relayApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + + /// It might happen that by accident we hit a session change + /// A block in which a session change occurs cannot hold any tx + /// Chopsticks does not have the notion of tx pool either, so we need to retry + /// Therefore we just retry at most MAX_BALANCE_TRANSFER_TRIES + const MAX_BALANCE_TRANSFER_TRIES = 5; + while (tries < MAX_BALANCE_TRANSFER_TRIES) { + const txHash = await relayApi.tx.balances + .transferAllowDeath(randomAccount.address, 1_000_000_000) + .signAndSend(alice); + await context.waitBlock(1); + + const block = await relayApi.rpc.chain.getBlock(); + const includedTxHashes = block.block.extrinsics.map((x) => x.hash.toString()); + if (includedTxHashes.includes(txHash.toString())) { + break; + } + tries++; + } + + const balanceAfter = (await relayApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + expect(balanceBefore < balanceAfter).to.be.true; + }, + }); }, }); diff --git a/test/suites/zombie_simple_template_upgrade/test_zombie_simple_template_upgrade.ts b/test/suites/zombie_simple_template_upgrade/test_zombie_simple_template_upgrade.ts index 6f2c569d1..dd19cd025 100644 --- a/test/suites/zombie_simple_template_upgrade/test_zombie_simple_template_upgrade.ts +++ b/test/suites/zombie_simple_template_upgrade/test_zombie_simple_template_upgrade.ts @@ -1,8 +1,8 @@ +import "@tanssi/api-augment"; import { MoonwallContext, beforeAll, describeSuite, expect } from "@moonwall/cli"; import type { KeyringPair } from "@moonwall/util"; import { type ApiPromise, Keyring } from "@polkadot/api"; -import { alith } from "@moonwall/util"; - +import { alith, generateKeyringPair } from "@moonwall/util"; import fs from "node:fs"; describeSuite({ @@ -38,26 +38,28 @@ describeSuite({ id: "T02", title: "Chain can be upgraded", timeout: 600000, - test: async () => { + test: async ({ skip }) => { const blockNumberBefore = (await paraApi.rpc.chain.getBlock()).block.header.number.toNumber(); const currentCode = await paraApi.rpc.state.getStorage(":code"); const codeString = currentCode.toString(); - const rtBefore = paraApi.consts.system.version.specVersion.toNumber(); const wasm = fs.readFileSync((await MoonwallContext.getContext()).rtUpgradePath); const rtHex = `0x${wasm.toString("hex")}`; + const rtBefore = paraApi.consts.system.version.specVersion.toNumber(); if (rtHex === codeString) { log("Runtime already upgraded, skipping test"); - return; + skip(); } + log("Current runtime spec version: ", rtBefore); log("Runtime not upgraded, proceeding with test"); log(`Current runtime hash: ${rtHex.slice(0, 10)}...${rtHex.slice(-10)}`); - log(`New runtime hash: ${codeString.slice(0, 10)}...${codeString.slice(-10)}`); + log(`New runtime bytes: ${codeString.slice(0, 10)}...${codeString.slice(-10)}`); await context.upgradeRuntime({ from: alice_or_alith, logger: log }); await context.waitBlock(2); const rtafter = paraApi.consts.system.version.specVersion.toNumber(); + log("New runtime spec version:", rtafter); if (rtBefore === rtafter) { throw new Error("Runtime upgrade failed"); } @@ -66,5 +68,39 @@ describeSuite({ expect(blockNumberAfter, "Block number did not increase").to.be.greaterThan(blockNumberBefore); }, }); + + it({ + id: "T03", + title: "Can send balance transfers", + timeout: 600000, + test: async () => { + const randomAccount = generateKeyringPair("sr25519"); + + let tries = 0; + const balanceBefore = (await paraApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + + /// It might happen that by accident we hit a session change + /// A block in which a session change occurs cannot hold any tx + /// Chopsticks does not have the notion of tx pool either, so we need to retry + /// Therefore we just retry at most MAX_BALANCE_TRANSFER_TRIES + const MAX_BALANCE_TRANSFER_TRIES = 5; + while (tries < MAX_BALANCE_TRANSFER_TRIES) { + const txHash = await paraApi.tx.balances + .transferAllowDeath(randomAccount.address, 1_000_000_000) + .signAndSend(alice_or_alith); + await context.waitBlock(1); + + const block = await paraApi.rpc.chain.getBlock(); + const includedTxHashes = block.block.extrinsics.map((x) => x.hash.toString()); + if (includedTxHashes.includes(txHash.toString())) { + break; + } + tries++; + } + + const balanceAfter = (await paraApi.query.system.account(randomAccount.address)).data.free.toBigInt(); + expect(balanceBefore < balanceAfter).to.be.true; + }, + }); }, }); diff --git a/test/suites/zombie_tanssi_relay_eth_bridge/test_zombie_tanssi_relay_eth_bridge.ts b/test/suites/zombie_tanssi_relay_eth_bridge/test_zombie_tanssi_relay_eth_bridge.ts index a508b67b0..5726e06f0 100644 --- a/test/suites/zombie_tanssi_relay_eth_bridge/test_zombie_tanssi_relay_eth_bridge.ts +++ b/test/suites/zombie_tanssi_relay_eth_bridge/test_zombie_tanssi_relay_eth_bridge.ts @@ -1,3 +1,4 @@ +import "@tanssi/api-augment/dancelight"; import { beforeAll, describeSuite, expect, afterAll } from "@moonwall/cli"; import { type ApiPromise, Keyring } from "@polkadot/api"; import { spawn, exec, type ChildProcessWithoutNullStreams } from "node:child_process"; @@ -317,7 +318,7 @@ describeSuite({ for (let i = 0; i < 3 * blocksPerSession; ++i) { const latestBlockHash = await relayApi.rpc.chain.getBlockHash(); const author = (await relayApi.derive.chain.getHeader(latestBlockHash)).author; - if (author === operatorAccount.address) { + if (author.toString() === operatorAccount.address) { return; } await context.waitBlock(1, "Tanssi-relay"); diff --git a/tools/iforgor/tanssi.toml b/tools/iforgor/tanssi.toml index 7d0f14caa..e91164d1f 100644 --- a/tools/iforgor/tanssi.toml +++ b/tools/iforgor/tanssi.toml @@ -58,9 +58,17 @@ cargo test --release --all --features fast-runtime name = "[Tanssi] Cargo Test Crate" only_in_dir = "**/tanssi" script = """ -cargo test --release -p $1 --features runtime-benchmarks +cargo test --release -p $1 --features=fast-runtime $2 """ -args = ["Which crate to test"] +args = ["Which crate to test", "Tests filter"] + +[[entries]] +name = "[Tanssi] Cargo Test Crate (with benchmarks)" +only_in_dir = "**/tanssi" +script = """ +cargo test --release -p $1 --features=fast-runtime,benchmarks $2 +""" +args = ["Which crate to test", "Tests filter"] ## Build