From 28da643820198b1407d86c1b22cedb19b78e6fb3 Mon Sep 17 00:00:00 2001 From: Andrea Giacobino Date: Fri, 26 Jul 2024 08:24:19 +0200 Subject: [PATCH] Add tracing for runtime-3100 (#110) * Add tracing sources for runtime-3100 * Add tracing WASM for runtime-3100 --- ...nbase-runtime-3100-substitute-tracing.json | 1 + ...nbeam-runtime-3100-substitute-tracing.json | 1 + ...river-runtime-3100-substitute-tracing.json | 1 + tracing/3100/Cargo.lock | 8112 +++++++++++++++++ tracing/3100/Cargo.toml | 454 + tracing/3100/runtime/common/Cargo.toml | 154 + tracing/3100/runtime/common/src/apis.rs | 1178 +++ .../3100/runtime/common/src/benchmarking.rs | 30 + .../common/src/impl_moonbeam_xcm_call.rs | 51 + .../src/impl_moonbeam_xcm_call_tracing.rs | 119 + .../src/impl_on_charge_evm_transaction.rs | 62 + .../common/src/impl_self_contained_call.rs | 78 + .../runtime/common/src/impl_xcm_evm_runner.rs | 242 + tracing/3100/runtime/common/src/lib.rs | 30 + tracing/3100/runtime/common/src/migrations.rs | 199 + tracing/3100/runtime/common/src/timestamp.rs | 92 + .../src/weights/cumulus_pallet_xcmp_queue.rs | 154 + .../3100/runtime/common/src/weights/mod.rs | 49 + .../src/weights/pallet_asset_manager.rs | 144 + .../common/src/weights/pallet_assets.rs | 485 + .../src/weights/pallet_author_inherent.rs | 70 + .../src/weights/pallet_author_mapping.rs | 122 + .../src/weights/pallet_author_slot_filter.rs | 59 + .../common/src/weights/pallet_balances.rs | 151 + .../common/src/weights/pallet_collective.rs | 308 + .../src/weights/pallet_conviction_voting.rs | 192 + .../src/weights/pallet_crowdloan_rewards.rs | 163 + .../runtime/common/src/weights/pallet_evm.rs | 80 + .../common/src/weights/pallet_identity.rs | 411 + .../weights/pallet_moonbeam_foreign_assets.rs | 173 + .../pallet_moonbeam_lazy_migrations.rs | 77 + .../src/weights/pallet_moonbeam_orbiters.rs | 203 + .../common/src/weights/pallet_multisig.rs | 160 + .../src/weights/pallet_parachain_staking.rs | 864 ++ .../weights/pallet_precompile_benchmarks.rs | 80 + .../common/src/weights/pallet_preimage.rs | 251 + .../common/src/weights/pallet_proxy.rs | 217 + .../common/src/weights/pallet_randomness.rs | 162 + .../common/src/weights/pallet_referenda.rs | 483 + .../src/weights/pallet_relay_storage_roots.rs | 64 + .../common/src/weights/pallet_scheduler.rs | 272 + .../runtime/common/src/weights/pallet_sudo.rs | 91 + .../common/src/weights/pallet_timestamp.rs | 67 + .../common/src/weights/pallet_treasury.rs | 189 + .../common/src/weights/pallet_utility.rs | 105 + .../common/src/weights/pallet_whitelist.rs | 118 + .../runtime/common/src/weights/pallet_xcm.rs | 336 + .../src/weights/pallet_xcm_transactor.rs | 204 + tracing/3100/runtime/moonbase/Cargo.toml | 430 + tracing/3100/runtime/moonbase/build.rs | 25 + .../3100/runtime/moonbase/src/asset_config.rs | 218 + .../moonbase/src/governance/councils.rs | 62 + .../runtime/moonbase/src/governance/mod.rs | 29 + .../moonbase/src/governance/origins.rs | 83 + .../moonbase/src/governance/referenda.rs | 101 + .../runtime/moonbase/src/governance/tracks.rs | 193 + tracing/3100/runtime/moonbase/src/lib.rs | 1840 ++++ .../3100/runtime/moonbase/src/migrations.rs | 28 + .../3100/runtime/moonbase/src/precompiles.rs | 352 + .../3100/runtime/moonbase/src/xcm_config.rs | 809 ++ .../3100/runtime/moonbase/tests/common/mod.rs | 405 + .../runtime/moonbase/tests/evm_tracing.rs | 144 + .../moonbase/tests/integration_test.rs | 3138 +++++++ .../runtime/moonbase/tests/runtime_apis.rs | 397 + .../runtime/moonbase/tests/xcm_mock/mod.rs | 272 + .../moonbase/tests/xcm_mock/parachain.rs | 1114 +++ .../moonbase/tests/xcm_mock/relay_chain.rs | 430 + .../moonbase/tests/xcm_mock/statemint_like.rs | 582 ++ .../3100/runtime/moonbase/tests/xcm_tests.rs | 3984 ++++++++ tracing/3100/runtime/moonbeam/Cargo.toml | 408 + tracing/3100/runtime/moonbeam/build.rs | 25 + .../3100/runtime/moonbeam/src/asset_config.rs | 216 + .../moonbeam/src/governance/councils.rs | 61 + .../runtime/moonbeam/src/governance/mod.rs | 29 + .../moonbeam/src/governance/origins.rs | 85 + .../moonbeam/src/governance/referenda.rs | 100 + .../runtime/moonbeam/src/governance/tracks.rs | 193 + tracing/3100/runtime/moonbeam/src/lib.rs | 1841 ++++ .../3100/runtime/moonbeam/src/migrations.rs | 368 + .../3100/runtime/moonbeam/src/precompiles.rs | 296 + .../3100/runtime/moonbeam/src/xcm_config.rs | 740 ++ .../3100/runtime/moonbeam/tests/common/mod.rs | 394 + .../runtime/moonbeam/tests/evm_tracing.rs | 144 + .../moonbeam/tests/integration_test.rs | 2896 ++++++ .../runtime/moonbeam/tests/runtime_apis.rs | 395 + .../runtime/moonbeam/tests/xcm_mock/mod.rs | 271 + .../moonbeam/tests/xcm_mock/parachain.rs | 1099 +++ .../moonbeam/tests/xcm_mock/relay_chain.rs | 430 + .../moonbeam/tests/xcm_mock/statemint_like.rs | 582 ++ .../3100/runtime/moonbeam/tests/xcm_tests.rs | 3701 ++++++++ tracing/3100/runtime/moonriver/Cargo.toml | 413 + tracing/3100/runtime/moonriver/build.rs | 25 + .../runtime/moonriver/src/asset_config.rs | 217 + .../moonriver/src/governance/councils.rs | 61 + .../runtime/moonriver/src/governance/mod.rs | 29 + .../moonriver/src/governance/origins.rs | 84 + .../moonriver/src/governance/referenda.rs | 100 + .../moonriver/src/governance/tracks.rs | 193 + tracing/3100/runtime/moonriver/src/lib.rs | 1842 ++++ .../3100/runtime/moonriver/src/migrations.rs | 31 + .../3100/runtime/moonriver/src/precompiles.rs | 269 + .../3100/runtime/moonriver/src/xcm_config.rs | 753 ++ .../runtime/moonriver/tests/common/mod.rs | 401 + .../runtime/moonriver/tests/evm_tracing.rs | 144 + .../moonriver/tests/integration_test.rs | 2805 ++++++ .../runtime/moonriver/tests/runtime_apis.rs | 398 + .../runtime/moonriver/tests/xcm_mock/mod.rs | 273 + .../moonriver/tests/xcm_mock/parachain.rs | 1105 +++ .../moonriver/tests/xcm_mock/relay_chain.rs | 430 + .../tests/xcm_mock/statemine_like.rs | 582 ++ .../3100/runtime/moonriver/tests/xcm_tests.rs | 4010 ++++++++ tracing/3100/rust-toolchain | 5 + tracing/3100/shared/primitives/ext/Cargo.toml | 33 + tracing/3100/shared/primitives/ext/src/lib.rs | 82 + .../shared/primitives/rpc/debug/Cargo.toml | 45 + .../shared/primitives/rpc/debug/src/lib.rs | 129 + .../rpc/evm-tracing-events/Cargo.toml | 37 + .../rpc/evm-tracing-events/src/evm.rs | 258 + .../rpc/evm-tracing-events/src/gasometer.rs | 119 + .../rpc/evm-tracing-events/src/lib.rs | 287 + .../rpc/evm-tracing-events/src/runtime.rs | 156 + .../3100/shared/runtime/evm_tracer/Cargo.toml | 51 + .../3100/shared/runtime/evm_tracer/src/lib.rs | 117 + ...nbase-runtime-3100-substitute-tracing.wasm | Bin 0 -> 2209177 bytes ...nbeam-runtime-3100-substitute-tracing.wasm | Bin 0 -> 2164747 bytes ...river-runtime-3100-substitute-tracing.wasm | Bin 0 -> 2162263 bytes 126 files changed, 61702 insertions(+) create mode 100644 srtool-digest/moonbase-runtime-3100-substitute-tracing.json create mode 100644 srtool-digest/moonbeam-runtime-3100-substitute-tracing.json create mode 100644 srtool-digest/moonriver-runtime-3100-substitute-tracing.json create mode 100644 tracing/3100/Cargo.lock create mode 100644 tracing/3100/Cargo.toml create mode 100644 tracing/3100/runtime/common/Cargo.toml create mode 100644 tracing/3100/runtime/common/src/apis.rs create mode 100644 tracing/3100/runtime/common/src/benchmarking.rs create mode 100644 tracing/3100/runtime/common/src/impl_moonbeam_xcm_call.rs create mode 100644 tracing/3100/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs create mode 100644 tracing/3100/runtime/common/src/impl_on_charge_evm_transaction.rs create mode 100644 tracing/3100/runtime/common/src/impl_self_contained_call.rs create mode 100644 tracing/3100/runtime/common/src/impl_xcm_evm_runner.rs create mode 100644 tracing/3100/runtime/common/src/lib.rs create mode 100644 tracing/3100/runtime/common/src/migrations.rs create mode 100644 tracing/3100/runtime/common/src/timestamp.rs create mode 100644 tracing/3100/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 tracing/3100/runtime/common/src/weights/mod.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_asset_manager.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_assets.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_author_inherent.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_author_mapping.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_author_slot_filter.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_balances.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_collective.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_conviction_voting.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_crowdloan_rewards.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_evm.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_identity.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_moonbeam_orbiters.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_multisig.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_parachain_staking.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_precompile_benchmarks.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_preimage.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_proxy.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_randomness.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_referenda.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_relay_storage_roots.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_scheduler.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_sudo.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_timestamp.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_treasury.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_utility.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_whitelist.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_xcm.rs create mode 100644 tracing/3100/runtime/common/src/weights/pallet_xcm_transactor.rs create mode 100644 tracing/3100/runtime/moonbase/Cargo.toml create mode 100644 tracing/3100/runtime/moonbase/build.rs create mode 100644 tracing/3100/runtime/moonbase/src/asset_config.rs create mode 100644 tracing/3100/runtime/moonbase/src/governance/councils.rs create mode 100644 tracing/3100/runtime/moonbase/src/governance/mod.rs create mode 100644 tracing/3100/runtime/moonbase/src/governance/origins.rs create mode 100644 tracing/3100/runtime/moonbase/src/governance/referenda.rs create mode 100644 tracing/3100/runtime/moonbase/src/governance/tracks.rs create mode 100644 tracing/3100/runtime/moonbase/src/lib.rs create mode 100644 tracing/3100/runtime/moonbase/src/migrations.rs create mode 100644 tracing/3100/runtime/moonbase/src/precompiles.rs create mode 100644 tracing/3100/runtime/moonbase/src/xcm_config.rs create mode 100644 tracing/3100/runtime/moonbase/tests/common/mod.rs create mode 100644 tracing/3100/runtime/moonbase/tests/evm_tracing.rs create mode 100644 tracing/3100/runtime/moonbase/tests/integration_test.rs create mode 100644 tracing/3100/runtime/moonbase/tests/runtime_apis.rs create mode 100644 tracing/3100/runtime/moonbase/tests/xcm_mock/mod.rs create mode 100644 tracing/3100/runtime/moonbase/tests/xcm_mock/parachain.rs create mode 100644 tracing/3100/runtime/moonbase/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3100/runtime/moonbase/tests/xcm_mock/statemint_like.rs create mode 100644 tracing/3100/runtime/moonbase/tests/xcm_tests.rs create mode 100644 tracing/3100/runtime/moonbeam/Cargo.toml create mode 100644 tracing/3100/runtime/moonbeam/build.rs create mode 100644 tracing/3100/runtime/moonbeam/src/asset_config.rs create mode 100644 tracing/3100/runtime/moonbeam/src/governance/councils.rs create mode 100644 tracing/3100/runtime/moonbeam/src/governance/mod.rs create mode 100644 tracing/3100/runtime/moonbeam/src/governance/origins.rs create mode 100644 tracing/3100/runtime/moonbeam/src/governance/referenda.rs create mode 100644 tracing/3100/runtime/moonbeam/src/governance/tracks.rs create mode 100644 tracing/3100/runtime/moonbeam/src/lib.rs create mode 100644 tracing/3100/runtime/moonbeam/src/migrations.rs create mode 100644 tracing/3100/runtime/moonbeam/src/precompiles.rs create mode 100644 tracing/3100/runtime/moonbeam/src/xcm_config.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/common/mod.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/evm_tracing.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/integration_test.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/runtime_apis.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/xcm_mock/mod.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/xcm_mock/parachain.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/xcm_mock/statemint_like.rs create mode 100644 tracing/3100/runtime/moonbeam/tests/xcm_tests.rs create mode 100644 tracing/3100/runtime/moonriver/Cargo.toml create mode 100644 tracing/3100/runtime/moonriver/build.rs create mode 100644 tracing/3100/runtime/moonriver/src/asset_config.rs create mode 100644 tracing/3100/runtime/moonriver/src/governance/councils.rs create mode 100644 tracing/3100/runtime/moonriver/src/governance/mod.rs create mode 100644 tracing/3100/runtime/moonriver/src/governance/origins.rs create mode 100644 tracing/3100/runtime/moonriver/src/governance/referenda.rs create mode 100644 tracing/3100/runtime/moonriver/src/governance/tracks.rs create mode 100644 tracing/3100/runtime/moonriver/src/lib.rs create mode 100644 tracing/3100/runtime/moonriver/src/migrations.rs create mode 100644 tracing/3100/runtime/moonriver/src/precompiles.rs create mode 100644 tracing/3100/runtime/moonriver/src/xcm_config.rs create mode 100644 tracing/3100/runtime/moonriver/tests/common/mod.rs create mode 100644 tracing/3100/runtime/moonriver/tests/evm_tracing.rs create mode 100644 tracing/3100/runtime/moonriver/tests/integration_test.rs create mode 100644 tracing/3100/runtime/moonriver/tests/runtime_apis.rs create mode 100644 tracing/3100/runtime/moonriver/tests/xcm_mock/mod.rs create mode 100644 tracing/3100/runtime/moonriver/tests/xcm_mock/parachain.rs create mode 100644 tracing/3100/runtime/moonriver/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3100/runtime/moonriver/tests/xcm_mock/statemine_like.rs create mode 100644 tracing/3100/runtime/moonriver/tests/xcm_tests.rs create mode 100644 tracing/3100/rust-toolchain create mode 100644 tracing/3100/shared/primitives/ext/Cargo.toml create mode 100644 tracing/3100/shared/primitives/ext/src/lib.rs create mode 100644 tracing/3100/shared/primitives/rpc/debug/Cargo.toml create mode 100644 tracing/3100/shared/primitives/rpc/debug/src/lib.rs create mode 100644 tracing/3100/shared/primitives/rpc/evm-tracing-events/Cargo.toml create mode 100644 tracing/3100/shared/primitives/rpc/evm-tracing-events/src/evm.rs create mode 100644 tracing/3100/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs create mode 100644 tracing/3100/shared/primitives/rpc/evm-tracing-events/src/lib.rs create mode 100644 tracing/3100/shared/primitives/rpc/evm-tracing-events/src/runtime.rs create mode 100644 tracing/3100/shared/runtime/evm_tracer/Cargo.toml create mode 100644 tracing/3100/shared/runtime/evm_tracer/src/lib.rs create mode 100644 wasm/moonbase-runtime-3100-substitute-tracing.wasm create mode 100644 wasm/moonbeam-runtime-3100-substitute-tracing.wasm create mode 100644 wasm/moonriver-runtime-3100-substitute-tracing.wasm diff --git a/srtool-digest/moonbase-runtime-3100-substitute-tracing.json b/srtool-digest/moonbase-runtime-3100-substitute-tracing.json new file mode 100644 index 00000000..b917940a --- /dev/null +++ b/srtool-digest/moonbase-runtime-3100-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbase-runtime","tmsp":"2024-07-25T22:58:00Z","size":"2209177","prop":"0xcce0f2f2d667f043dcaddce81a4650a9ac67b243d1c6848cce3535704e278e65","authorize_upgrade_prop":"0xbca5dd51d56214c91388e36b109abff88529498394b0b12a866468112026909d","ipfs":"QmcFp7rxhD4iCZDcW8Tidw2hm39QazMBhTc6akQSz8HtwR","sha256":"0x257e2d3e75c60aca40a4e5103b7fb5ea4eba6db9211e1bb01cec3cccc62a907f","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbase-runtime","profile":"release"},"context":{"package":"moonbase-runtime","runtime_dir":"runtime/moonbase","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-07-25T22:57:40Z","size":"10597627","prop":"0xb8410207db4e6685a991a0769c45ce13f582fda9427f1ece37964affc75d5fdf","authorize_upgrade_prop":"0x348c684cc4ae1fe4ae5e4339ec3fad5439135b4df9cc2b139afc26486f55128e","blake2_256":"0xb42cc7eb800ae77f5e3d37ad655e8b0ad7720520650d9a71d893a80e246d0ae8","ipfs":"QmNRB9DqwxpFNZAMpomyJd8pG5mdQ2tXFm6S4T8UtMMsY7","sha256":"0xbbe7278d7aa4eba2594565a78284c14917956dc8cdd5d269e53340843b316efa","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.wasm","subwasm":{"size":10597627,"compression":{"size_compressed":10597627,"size_decompressed":10597627,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbase","implName":"moonbase","authoringVersion":4,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0xb8410207db4e6685a991a0769c45ce13f582fda9427f1ece37964affc75d5fdf","parachain_authorize_upgrade_hash":"0x348c684cc4ae1fe4ae5e4339ec3fad5439135b4df9cc2b139afc26486f55128e","ipfs_hash":"QmNRB9DqwxpFNZAMpomyJd8pG5mdQ2tXFm6S4T8UtMMsY7","blake2_256":"0xb42cc7eb800ae77f5e3d37ad655e8b0ad7720520650d9a71d893a80e246d0ae8"}},"compressed":{"tmsp":"2024-07-25T22:53:53Z","size":"2209177","prop":"0xcce0f2f2d667f043dcaddce81a4650a9ac67b243d1c6848cce3535704e278e65","authorize_upgrade_prop":"0xbca5dd51d56214c91388e36b109abff88529498394b0b12a866468112026909d","blake2_256":"0xaab5be6a9f9c38197eba55405fdc2ab0085597ef9d84d4ef45fe49e02507640f","ipfs":"QmcFp7rxhD4iCZDcW8Tidw2hm39QazMBhTc6akQSz8HtwR","sha256":"0x257e2d3e75c60aca40a4e5103b7fb5ea4eba6db9211e1bb01cec3cccc62a907f","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.compressed.wasm","subwasm":{"size":2209177,"compression":{"size_compressed":2209177,"size_decompressed":10597627,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbase","implName":"moonbase","authoringVersion":4,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0xcce0f2f2d667f043dcaddce81a4650a9ac67b243d1c6848cce3535704e278e65","parachain_authorize_upgrade_hash":"0xbca5dd51d56214c91388e36b109abff88529498394b0b12a866468112026909d","ipfs_hash":"QmcFp7rxhD4iCZDcW8Tidw2hm39QazMBhTc6akQSz8HtwR","blake2_256":"0xaab5be6a9f9c38197eba55405fdc2ab0085597ef9d84d4ef45fe49e02507640f"}}}} diff --git a/srtool-digest/moonbeam-runtime-3100-substitute-tracing.json b/srtool-digest/moonbeam-runtime-3100-substitute-tracing.json new file mode 100644 index 00000000..d4ee5565 --- /dev/null +++ b/srtool-digest/moonbeam-runtime-3100-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbeam-runtime","tmsp":"2024-07-25T23:11:34Z","size":"2164747","prop":"0xc05a84719d1454a8e509c5e518bcac43fe0a65dee1cf4e39e69ba7aa37a4dd2b","authorize_upgrade_prop":"0x87efbe2909cd1bd063be5b728f9215d979f6ff22efa1bf53f2d34eab17a6a632","ipfs":"Qma8GUZbk2tVj6ZerqbYPkYzjVTnpwSrcEVhJvwUn3AAkR","sha256":"0x735e222127ef025be5c3e8980061d690ab1732ffe2aa92d0146a4ff0ec806dfc","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbeam-runtime","profile":"release"},"context":{"package":"moonbeam-runtime","runtime_dir":"runtime/moonbeam","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-07-25T23:11:15Z","size":"10377260","prop":"0xf6610e7d94572d8e34e6d4eeab358789ac44eb6a0f73c255d1c9a8aec99bbc4b","authorize_upgrade_prop":"0x266d5a61f4da5906abbb7d85597c6b3fadf39b5d4dc183e0d50a2c11e13c349c","blake2_256":"0xfe5bb25735b313abdcfd05a5b50baca68076d3a0c134e042bab06ec5caa5d0d0","ipfs":"QmPbNFNrJsXp3Aw7LVLQC1b1ashqiVSpHswSYzGbUhRWEq","sha256":"0x60a15884d1df7b57c1d43a5de7923472af8761f9172b22640a696afb17c12874","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.wasm","subwasm":{"size":10377260,"compression":{"size_compressed":10377260,"size_decompressed":10377260,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbeam","implName":"moonbeam","authoringVersion":3,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0xf6610e7d94572d8e34e6d4eeab358789ac44eb6a0f73c255d1c9a8aec99bbc4b","parachain_authorize_upgrade_hash":"0x266d5a61f4da5906abbb7d85597c6b3fadf39b5d4dc183e0d50a2c11e13c349c","ipfs_hash":"QmPbNFNrJsXp3Aw7LVLQC1b1ashqiVSpHswSYzGbUhRWEq","blake2_256":"0xfe5bb25735b313abdcfd05a5b50baca68076d3a0c134e042bab06ec5caa5d0d0"}},"compressed":{"tmsp":"2024-07-25T23:07:30Z","size":"2164747","prop":"0xc05a84719d1454a8e509c5e518bcac43fe0a65dee1cf4e39e69ba7aa37a4dd2b","authorize_upgrade_prop":"0x87efbe2909cd1bd063be5b728f9215d979f6ff22efa1bf53f2d34eab17a6a632","blake2_256":"0xe7a4dbaf24ae471654c5520526c569bb03089f3e64c9dfa0318f999d0d7b93d4","ipfs":"Qma8GUZbk2tVj6ZerqbYPkYzjVTnpwSrcEVhJvwUn3AAkR","sha256":"0x735e222127ef025be5c3e8980061d690ab1732ffe2aa92d0146a4ff0ec806dfc","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.compressed.wasm","subwasm":{"size":2164747,"compression":{"size_compressed":2164747,"size_decompressed":10377260,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbeam","implName":"moonbeam","authoringVersion":3,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0xc05a84719d1454a8e509c5e518bcac43fe0a65dee1cf4e39e69ba7aa37a4dd2b","parachain_authorize_upgrade_hash":"0x87efbe2909cd1bd063be5b728f9215d979f6ff22efa1bf53f2d34eab17a6a632","ipfs_hash":"Qma8GUZbk2tVj6ZerqbYPkYzjVTnpwSrcEVhJvwUn3AAkR","blake2_256":"0xe7a4dbaf24ae471654c5520526c569bb03089f3e64c9dfa0318f999d0d7b93d4"}}}} diff --git a/srtool-digest/moonriver-runtime-3100-substitute-tracing.json b/srtool-digest/moonriver-runtime-3100-substitute-tracing.json new file mode 100644 index 00000000..a3c9a705 --- /dev/null +++ b/srtool-digest/moonriver-runtime-3100-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonriver-runtime","tmsp":"2024-07-25T23:04:49Z","size":"2162263","prop":"0xe18e91a07750bf09fbd158ff65a979d40c95420e07ac1cfe51a5dff253835864","authorize_upgrade_prop":"0x13cc2d3b4828dea193cf8182debc3c7b8d84eeac21e6e434851ca6f7fb267c73","ipfs":"QmeVo9duMAWYHPBd4caHMCSpcjLTCXsmPgJJkHzjY51yKm","sha256":"0x4654184ac1d42ef5b57a1a79c0a991d22a8c902a819c82d2554c7592d1a9495d","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonriver-runtime","profile":"release"},"context":{"package":"moonriver-runtime","runtime_dir":"runtime/moonriver","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-07-25T23:04:30Z","size":"10343766","prop":"0x2b25a9659cdffe7b40a3624dd9f6b6755d64d9c4ffa6b198b264b838cb6379e4","authorize_upgrade_prop":"0x9a1a7ad93349a6dc2ac92c91ae11c21754ca28a40bd8f10f53250a635b8be8c5","blake2_256":"0xa6e050a18e96e5511366b0554744c2a24417dc2c91d28ab0c1f9e9fd42734f78","ipfs":"Qmc2WPUWjHJ5j7S8Q3QbMhKwwdvVavwpFPWNMZSTdmB8oJ","sha256":"0x5891395d8b814244a9b941dd1430f5024c1b2be1dd397b4d689fb5906b9eca6b","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.wasm","subwasm":{"size":10343766,"compression":{"size_compressed":10343766,"size_decompressed":10343766,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonriver","implName":"moonriver","authoringVersion":3,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0x2b25a9659cdffe7b40a3624dd9f6b6755d64d9c4ffa6b198b264b838cb6379e4","parachain_authorize_upgrade_hash":"0x9a1a7ad93349a6dc2ac92c91ae11c21754ca28a40bd8f10f53250a635b8be8c5","ipfs_hash":"Qmc2WPUWjHJ5j7S8Q3QbMhKwwdvVavwpFPWNMZSTdmB8oJ","blake2_256":"0xa6e050a18e96e5511366b0554744c2a24417dc2c91d28ab0c1f9e9fd42734f78"}},"compressed":{"tmsp":"2024-07-25T23:00:45Z","size":"2162263","prop":"0xe18e91a07750bf09fbd158ff65a979d40c95420e07ac1cfe51a5dff253835864","authorize_upgrade_prop":"0x13cc2d3b4828dea193cf8182debc3c7b8d84eeac21e6e434851ca6f7fb267c73","blake2_256":"0x74300997e127a5f5a3d13a3164848677911cc972152342e8744be921b5228cf7","ipfs":"QmeVo9duMAWYHPBd4caHMCSpcjLTCXsmPgJJkHzjY51yKm","sha256":"0x4654184ac1d42ef5b57a1a79c0a991d22a8c902a819c82d2554c7592d1a9495d","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.compressed.wasm","subwasm":{"size":2162263,"compression":{"size_compressed":2162263,"size_decompressed":10343766,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonriver","implName":"moonriver","authoringVersion":3,"specVersion":3100,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":2,"stateVersion":0},"proposal_hash":"0xe18e91a07750bf09fbd158ff65a979d40c95420e07ac1cfe51a5dff253835864","parachain_authorize_upgrade_hash":"0x13cc2d3b4828dea193cf8182debc3c7b8d84eeac21e6e434851ca6f7fb267c73","ipfs_hash":"QmeVo9duMAWYHPBd4caHMCSpcjLTCXsmPgJJkHzjY51yKm","blake2_256":"0x74300997e127a5f5a3d13a3164848677911cc972152342e8744be921b5228cf7"}}}} diff --git a/tracing/3100/Cargo.lock b/tracing/3100/Cargo.lock new file mode 100644 index 00000000..75405d2b --- /dev/null +++ b/tracing/3100/Cargo.lock @@ -0,0 +1,8112 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "account" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "blake2-rfc", + "impl-serde 0.3.2", + "libsecp256k1", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "aquamarine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "ark-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bls12-381-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bw6-761" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bw6-761-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" +dependencies = [ + "ark-bw6-761", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-models-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-scale" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f69c00b3b529be29528a6f2fd5fa7b1790f8bed81b9cdca17e326538545a179" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ark-secret-scalar" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "ark-transcript", + "digest 0.10.7", + "getrandom_or_panic", + "zeroize", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", + "rayon", +] + +[[package]] +name = "ark-transcript" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.7", + "rand_core 0.6.4", + "sha3", +] + +[[package]] +name = "array-bytes" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-backing-primitives" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "sp-api", + "sp-consensus-slots", +] + +[[package]] +name = "async-trait" +version = "0.1.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bandersnatch_vrfs" +version = "0.0.4" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-serialize", + "ark-std", + "dleq_vrf", + "fflonk", + "merlin", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "ring", + "sha2 0.10.8", + "sp-ark-bls12-381", + "sp-ark-ed-on-bls12-381-bandersnatch", + "zeroize", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "serde", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec 0.4.12", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bounded-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bp-xcm-bridge-hub-router" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata 0.1.10", +] + +[[package]] +name = "build-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +dependencies = [ + "semver 0.6.0", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.22", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "case" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c" + +[[package]] +name = "cc" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-expr" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "common" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "fflonk", + "getrandom_or_panic", + "merlin", + "rand_chacha 0.3.1", +] + +[[package]] +name = "common-path" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "constcat" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "cumulus-pallet-dmp-queue" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "cumulus-pallet-parachain-system" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bytes", + "cumulus-pallet-parachain-system-proc-macro", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-core", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "staging-xcm", + "trie-db", +] + +[[package]] +name = "cumulus-pallet-parachain-system-proc-macro" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cumulus-pallet-xcm" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "cumulus-pallet-xcmp-queue" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bounded-collections", + "bp-xcm-bridge-hub-router", + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "cumulus-primitives-core" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-primitives", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", + "sp-trie", + "staging-xcm", +] + +[[package]] +name = "cumulus-primitives-parachain-inherent" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "cumulus-primitives-proof-size-hostfunction" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "sp-externalities", + "sp-runtime-interface", + "sp-trie", +] + +[[package]] +name = "cumulus-primitives-timestamp" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "futures", + "parity-scale-codec", + "sp-inherents", + "sp-std", + "sp-timestamp", +] + +[[package]] +name = "cumulus-primitives-utility" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "log", + "pallet-asset-conversion", + "parity-scale-codec", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cxx" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5262a7fa3f0bae2a55b767c223ba98032d7c328f5c13fa5cdc980b77fc0658" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.66", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dleq_vrf" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-scale", + "ark-secret-scalar", + "ark-serialize", + "ark-std", + "ark-transcript", + "arrayvec 0.7.4", + "zeroize", +] + +[[package]] +name = "docify" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce" +dependencies = [ + "docify_macros", +] + +[[package]] +name = "docify_macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" +dependencies = [ + "common-path", + "derive-syn-parse 0.2.0", + "once_cell", + "proc-macro2", + "quote", + "regex", + "syn 2.0.66", + "termcolor", + "toml", + "walkdir", +] + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.2", + "ed25519", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "enumflags2" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "enumn" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04d24d20b8ff2235cffbf242d5092de3aa45f77c5270ddbfadd2778ca13fea" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db", + "hash256-std-hasher", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sha3", + "trie-root", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "evm" +version = "0.41.1" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#5ebf882aa99ba449ecf01ba3c29a00ab05cffb17" +dependencies = [ + "auto_impl", + "environmental", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", + "log", + "parity-scale-codec", + "primitive-types", + "rlp", + "scale-info", + "serde", + "sha3", +] + +[[package]] +name = "evm-core" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#5ebf882aa99ba449ecf01ba3c29a00ab05cffb17" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-info", + "serde", +] + +[[package]] +name = "evm-gasometer" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#5ebf882aa99ba449ecf01ba3c29a00ab05cffb17" +dependencies = [ + "environmental", + "evm-core", + "evm-runtime", + "primitive-types", +] + +[[package]] +name = "evm-runtime" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#5ebf882aa99ba449ecf01ba3c29a00ab05cffb17" +dependencies = [ + "auto_impl", + "environmental", + "evm-core", + "primitive-types", + "sha3", +] + +[[package]] +name = "evm-tracing-events" +version = "0.1.0" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "evm", + "evm-gasometer", + "evm-runtime", + "parity-scale-codec", + "sp-runtime-interface", +] + +[[package]] +name = "expander" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "faster-hex" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fflonk" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fp-account" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "hex", + "impl-serde 0.4.0", + "libsecp256k1", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", +] + +[[package]] +name = "fp-consensus" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "ethereum", + "parity-scale-codec", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "fp-ethereum" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm", + "frame-support", + "parity-scale-codec", +] + +[[package]] +name = "fp-evm" +version = "3.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "evm", + "frame-support", + "num_enum 0.7.2", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "fp-rpc" +version = "3.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "fp-self-contained" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", +] + +[[package]] +name = "fp-storage" +version = "2.0.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "parity-scale-codec", + "serde", +] + +[[package]] +name = "frame-benchmarking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-support-procedural", + "frame-system", + "linregress", + "log", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "static_assertions", +] + +[[package]] +name = "frame-election-provider-solution-type" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-election-provider-support" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-election-provider-solution-type", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "frame-executive" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "aquamarine 0.3.3", + "frame-support", + "frame-system", + "frame-try-runtime", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "frame-metadata" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-support" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "aquamarine 0.5.0", + "array-bytes", + "bitflags 1.3.2", + "docify", + "environmental", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "k256", + "log", + "macro_magic", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "serde_json", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-crypto-hashing-proc-macro", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-metadata-ir", + "sp-runtime", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-weights", + "static_assertions", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "23.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse 0.2.0", + "expander", + "frame-support-procedural-tools", + "itertools", + "macro_magic", + "proc-macro-warning", + "proc-macro2", + "quote", + "sp-crypto-hashing", + "syn 2.0.66", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "10.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "11.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-system" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cfg-if", + "docify", + "frame-support", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", + "sp-weights", +] + +[[package]] +name = "frame-system-benchmarking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "frame-system-rpc-runtime-api" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "frame-try-runtime" +version = "0.34.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom_or_panic" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" +dependencies = [ + "rand", + "rand_core 0.6.4", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2 0.10.8", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + +[[package]] +name = "linregress" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" +dependencies = [ + "nalgebra", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "macro_magic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" +dependencies = [ + "const-random", + "derive-syn-parse 0.1.5", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_core_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" +dependencies = [ + "macro_magic_core", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memory-db" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" +dependencies = [ + "hash-db", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "moonbase-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-emergency-para-xcm", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-storage-cleaner", + "pallet-evm-precompile-xcm", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-foreign-asset-migrator", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-core-primitives" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-self-contained", + "hex-literal 0.3.4", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "moonbeam-evm-tracer" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "evm", + "evm-gasometer", + "evm-runtime", + "evm-tracing-events", + "fp-evm", + "moonbeam-primitives-ext", + "pallet-evm", + "parity-scale-codec", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-primitives-ext" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "evm-tracing-events", + "parity-scale-codec", + "sp-externalities", + "sp-runtime-interface", + "sp-std", +] + +[[package]] +name = "moonbeam-relay-encoder" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "frame-system", + "pallet-evm-precompile-relay-encoder", + "pallet-staking", + "pallet-xcm-transactor", + "parity-scale-codec", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-rpc-primitives-debug" +version = "0.1.0" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "hex", + "parity-scale-codec", + "serde", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-rpc-primitives-txpool" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "ethereum", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-runtime-common" +version = "0.8.0-dev" +dependencies = [ + "account", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "fp-ethereum", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "frame-try-runtime", + "hex-literal 0.3.4", + "impl-trait-for-tuples", + "log", + "moonbeam-core-primitives", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-identity", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-scheduler", + "pallet-sudo", + "pallet-timestamp", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-transactor", + "parity-scale-codec", + "precompile-utils", + "sp-api", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-runtime-common" +version = "0.8.0-dev" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "fp-ethereum", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "frame-try-runtime", + "hex-literal 0.3.4", + "impl-trait-for-tuples", + "log", + "moonbeam-core-primitives", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-identity", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-scheduler", + "pallet-sudo", + "pallet-timestamp", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-transactor", + "parity-scale-codec", + "precompile-utils", + "sp-api", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-xcm-benchmarks" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-erc20-xcm-bridge", + "pallet-xcm-benchmarks", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "staging-xcm", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonriver-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "nalgebra" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "nimbus-primitives" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "async-trait", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-inherents", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.4", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive 0.7.2", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "orml-traits" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#b86bc7dda8cc59e57c8b5dcfa813ebdbf76bee0e" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "num-traits", + "orml-utilities", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "orml-utilities" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#b86bc7dda8cc59e57c8b5dcfa813ebdbf76bee0e" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "orml-xcm-support" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#b86bc7dda8cc59e57c8b5dcfa813ebdbf76bee0e" +dependencies = [ + "frame-support", + "orml-traits", + "parity-scale-codec", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "orml-xtokens" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#b86bc7dda8cc59e57c8b5dcfa813ebdbf76bee0e" +dependencies = [ + "frame-support", + "frame-system", + "log", + "orml-traits", + "orml-xcm-support", + "pallet-xcm", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "pallet-asset-conversion" +version = "10.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-asset-manager" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-asset-rate" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-asset-tx-payment" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-assets" +version = "29.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-async-backing" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-consensus-slots", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-inherent" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-inherents", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-mapping" +version = "2.0.5" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "session-keys-primitives", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-slot-filter" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-authority-discovery" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-authority-discovery", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-authorship" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-babe" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-balances" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-broker" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-collator-selection" +version = "9.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-balances", + "pallet-session", + "parity-scale-codec", + "rand", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-collective" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-conviction-voting" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-crowdloan-rewards" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/crowdloan-rewards?branch=moonbeam-polkadot-v1.11.0#35d34816f5b4655d2192633d0d69531e4ed35f66" +dependencies = [ + "ed25519-dalek", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-utility", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-election-provider-multi-phase" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-election-provider-support-benchmarking", + "parity-scale-codec", + "rand", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", + "strum 0.26.2", +] + +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-system", + "parity-scale-codec", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-emergency-para-xcm" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-erc20-xcm-bridge" +version = "1.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "environmental", + "ethereum-types", + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-ethereum" +version = "4.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "evm", + "fp-consensus", + "fp-ethereum", + "fp-evm", + "fp-rpc", + "fp-storage", + "frame-support", + "frame-system", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", +] + +[[package]] +name = "pallet-ethereum-xcm" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "fp-ethereum", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm" +version = "6.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "environmental", + "evm", + "fp-account", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "hash-db", + "hex", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "rlp", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-chain-id" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "pallet-evm-precompile-author-mapping" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "num_enum 0.5.11", + "pallet-author-mapping", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-balances-erc20" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-balances", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-batch" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-blake2" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", +] + +[[package]] +name = "pallet-evm-precompile-bn128" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "sp-core", + "substrate-bn", +] + +[[package]] +name = "pallet-evm-precompile-call-permit" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-collective" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-collective", + "pallet-evm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-conviction-voting" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-conviction-voting", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-crowdloan-rewards" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-crowdloan-rewards", + "pallet-evm", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-dispatch" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "frame-support", + "pallet-evm", + "parity-scale-codec", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-precompile-gmp" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "orml-traits", + "orml-xtokens", + "pallet-evm", + "pallet-xcm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-identity" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "enumflags2", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "pallet-identity", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-modexp" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "num", +] + +[[package]] +name = "pallet-evm-precompile-p256verify" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "p256", +] + +[[package]] +name = "pallet-evm-precompile-parachain-staking" +version = "1.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-parachain-staking", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-consensus-slots", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-preimage" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-preimage", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-proxy" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-balances", + "pallet-evm", + "pallet-proxy", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-randomness" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "num_enum 0.5.11", + "pallet-evm", + "pallet-randomness", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-referenda" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-referenda", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-registry" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-relay-encoder" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-staking", + "pallet-xcm-transactor", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-relay-verifier" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "fp-evm", + "frame-support", + "frame-system", + "moonbeam-runtime-common 0.8.0-dev (git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100)", + "pallet-evm", + "pallet-precompile-benchmarks", + "pallet-relay-storage-roots", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-std", + "storage-proof-primitives", +] + +[[package]] +name = "pallet-evm-precompile-sha3fips" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "tiny-keccak", +] + +[[package]] +name = "pallet-evm-precompile-simple" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "ripemd", + "sp-io", +] + +[[package]] +name = "pallet-evm-precompile-storage-cleaner" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-precompile-xcm" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.7.2", + "pallet-evm", + "pallet-xcm", + "precompile-utils", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-evm-precompile-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-xcm-transactor", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-xcm-utils" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "num_enum 0.5.11", + "pallet-evm", + "pallet-xcm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-xtokens" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "orml-xtokens", + "pallet-evm", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompileset-assets-erc20" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-assets", + "pallet-balances", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-fast-unstake" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-identity" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-maintenance-mode" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-message-queue" +version = "31.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "pallet-migrations" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-moonbeam-foreign-assets" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "ethereum-types", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "precompile-utils-macro", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-moonbeam-lazy-migrations" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-assets", + "pallet-balances", + "pallet-evm", + "pallet-scheduler", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-moonbeam-orbiters" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-multisig" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-parachain-staking" +version = "3.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-slots", + "sp-runtime", + "sp-std", + "substrate-fixed", +] + +[[package]] +name = "pallet-precompile-benchmarks" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-evm-precompile-p256verify", + "pallet-relay-storage-roots", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-std", + "storage-proof-primitives", +] + +[[package]] +name = "pallet-preimage" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-proxy" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-proxy-genesis-companion" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "frame-support", + "frame-system", + "pallet-proxy", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-randomness" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "nimbus-primitives", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "schnorrkel", + "serde", + "session-keys-primitives", + "sp-consensus-babe", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-referenda" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-relay-storage-roots" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-root-testing" +version = "4.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-scheduler" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "pallet-session" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-society" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-staking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-staking-reward-fn" +version = "19.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "log", + "sp-arithmetic", +] + +[[package]] +name = "pallet-sudo" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-timestamp" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-std", + "sp-storage", + "sp-timestamp", +] + +[[package]] +name = "pallet-transaction-payment" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-transaction-payment-rpc-runtime-api" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "pallet-transaction-payment", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "pallet-treasury" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-utility" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-vesting" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-whitelist" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-xcm" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bounded-collections", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", +] + +[[package]] +name = "pallet-xcm-benchmarks" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "orml-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "parachains-common" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-support", + "frame-system", + "log", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-message-queue", + "pallet-xcm", + "parity-scale-codec", + "polkadot-primitives", + "scale-info", + "sp-consensus-aura", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-executor", + "substrate-wasm-builder", +] + +[[package]] +name = "parity-bip39" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" +dependencies = [ + "bitcoin_hashes", + "rand", + "rand_core 0.6.4", + "serde", + "unicode-normalization", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "password-hash", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "polkadot-core-primitives" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "polkadot-parachain-primitives" +version = "6.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bounded-collections", + "derive_more", + "parity-scale-codec", + "polkadot-core-primitives", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "polkadot-primitives" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bitvec", + "hex-literal 0.4.1", + "log", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-authority-discovery", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "polkadot-runtime-common" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "libsecp256k1", + "log", + "pallet-asset-rate", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-broker", + "pallet-election-provider-multi-phase", + "pallet-fast-unstake", + "pallet-identity", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-fn", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-vesting", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "slot-range-helper", + "sp-api", + "sp-core", + "sp-inherents", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "static_assertions", +] + +[[package]] +name = "polkadot-runtime-metrics" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bs58", + "frame-benchmarking", + "parity-scale-codec", + "polkadot-primitives", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "polkadot-runtime-parachains" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bitflags 1.3.2", + "bitvec", + "derive_more", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-broker", + "pallet-message-queue", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "pallet-vesting", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-primitives", + "polkadot-runtime-metrics", + "rand", + "rand_chacha 0.3.1", + "rustc-hex", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "staging-xcm", + "staging-xcm-executor", + "static_assertions", +] + +[[package]] +name = "polkavm-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" + +[[package]] +name = "polkavm-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" +dependencies = [ + "polkavm-derive-impl-macro", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" +dependencies = [ + "polkavm-common", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" +dependencies = [ + "polkavm-derive-impl", + "syn 2.0.66", +] + +[[package]] +name = "polkavm-linker" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" +dependencies = [ + "gimli", + "hashbrown 0.14.3", + "log", + "object", + "polkavm-common", + "regalloc2", + "rustc-demangle", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precompile-foreign-asset-migrator" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-asset-manager", + "pallet-assets", + "pallet-balances", + "pallet-evm", + "pallet-moonbeam-foreign-assets", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "precompile-utils" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "derive_more", + "environmental", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "hex", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "log", + "num_enum 0.7.2", + "pallet-evm", + "parity-scale-codec", + "precompile-utils-macro", + "scale-info", + "serde", + "similar-asserts", + "sp-core", + "sp-io", + "sp-runtime", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "precompile-utils-macro" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#45d16ae4c8b32e26fdab8353b704fd59ea0ddb8c" +dependencies = [ + "case", + "num_enum 0.7.2", + "prettyplease", + "proc-macro2", + "quote", + "sp-crypto-hashing", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.66", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-warning" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "ref-cast" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "blake2", + "common", + "fflonk", + "merlin", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.22", +] + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.11", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" +dependencies = [ + "aead", + "arrayref", + "arrayvec 0.7.4", + "curve25519-dalek 4.1.2", + "getrandom_or_panic", + "merlin", + "rand_core 0.6.4", + "serde_bytes", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "session-keys-primitives" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "async-trait", + "frame-support", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +dependencies = [ + "bstr", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e041bb827d1bfca18f213411d51b665309f1afb37a04a5d1464530e13779fc0f" +dependencies = [ + "console", + "similar", +] + +[[package]] +name = "simple-mermaid" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "slices" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2086e458a369cdca838e9f6ed04b4cc2e3ce636d99abb80c9e2eada107749cf" +dependencies = [ + "faster-hex", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "slot-range-helper" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "enumn", + "parity-scale-codec", + "paste", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "sp-api" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro", + "sp-core", + "sp-externalities", + "sp-metadata-ir", + "sp-runtime", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "thiserror", +] + +[[package]] +name = "sp-api-proc-macro" +version = "15.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "Inflector", + "blake2", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-application-crypto" +version = "30.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-arithmetic" +version = "23.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "static_assertions", +] + +[[package]] +name = "sp-ark-bls12-381" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-bls12-381-ext", + "sp-crypto-ec-utils", +] + +[[package]] +name = "sp-ark-ed-on-bls12-381-bandersnatch" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-ed-on-bls12-381-bandersnatch-ext", + "sp-crypto-ec-utils", +] + +[[package]] +name = "sp-authority-discovery" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-runtime", +] + +[[package]] +name = "sp-block-builder" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "sp-api", + "sp-inherents", + "sp-runtime", +] + +[[package]] +name = "sp-consensus-aura" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-consensus-slots", + "sp-inherents", + "sp-runtime", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-babe" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-slots" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-timestamp", +] + +[[package]] +name = "sp-core" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "array-bytes", + "bandersnatch_vrfs", + "bitflags 1.3.2", + "blake2", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot", + "paste", + "primitive-types", + "rand", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-crypto-hashing", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + +[[package]] +name = "sp-crypto-ec-utils" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "ark-bls12-377", + "ark-bls12-377-ext", + "ark-bls12-381", + "ark-bls12-381-ext", + "ark-bw6-761", + "ark-bw6-761-ext", + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "ark-scale", + "sp-runtime-interface", +] + +[[package]] +name = "sp-crypto-hashing" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.7", + "sha2 0.10.8", + "sha3", + "twox-hash", +] + +[[package]] +name = "sp-crypto-hashing-proc-macro" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "quote", + "sp-crypto-hashing", + "syn 2.0.66", +] + +[[package]] +name = "sp-debug-derive" +version = "14.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-externalities" +version = "0.25.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-storage", +] + +[[package]] +name = "sp-genesis-builder" +version = "0.8.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde_json", + "sp-api", + "sp-runtime", +] + +[[package]] +name = "sp-inherents" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sp-io" +version = "30.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bytes", + "ed25519-dalek", + "libsecp256k1", + "log", + "parity-scale-codec", + "polkavm-derive", + "rustversion", + "secp256k1", + "sp-core", + "sp-crypto-hashing", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-trie", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keystore" +version = "0.34.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "parking_lot", + "sp-core", + "sp-externalities", +] + +[[package]] +name = "sp-maybe-compressed-blob" +version = "11.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "thiserror", + "zstd", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp-npos-elections" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-offchain" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "sp-api", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-panic-handler" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-runtime" +version = "31.0.1" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "docify", + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand", + "scale-info", + "serde", + "simple-mermaid", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std", + "sp-weights", +] + +[[package]] +name = "sp-runtime-interface" +version = "24.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "17.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "Inflector", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-session" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-staking", +] + +[[package]] +name = "sp-staking" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-state-machine" +version = "0.35.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot", + "rand", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-trie", + "thiserror", + "tracing", + "trie-db", +] + +[[package]] +name = "sp-std" +version = "14.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" + +[[package]] +name = "sp-storage" +version = "19.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", +] + +[[package]] +name = "sp-timestamp" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "async-trait", + "parity-scale-codec", + "sp-inherents", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sp-tracing" +version = "16.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-transaction-pool" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "sp-api", + "sp-runtime", +] + +[[package]] +name = "sp-trie" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "ahash 0.8.11", + "hash-db", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot", + "rand", + "scale-info", + "schnellru", + "sp-core", + "sp-externalities", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-crypto-hashing-proc-macro", + "sp-runtime", + "sp-std", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "parity-scale-codec", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-wasm-interface" +version = "20.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "impl-trait-for-tuples", + "log", + "parity-scale-codec", +] + +[[package]] +name = "sp-weights" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "bounded-collections", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-debug-derive", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "ss58-registry" +version = "1.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4743ce898933fbff7bbf414f497c459a782d496269644b3d650a398ae6a487ba" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "staging-parachain-info" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "staging-xcm" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "array-bytes", + "bounded-collections", + "derivative", + "environmental", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-weights", + "xcm-procedural", +] + +[[package]] +name = "staging-xcm-builder" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-transaction-payment", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "staging-xcm-executor" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "storage-proof-primitives" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.66", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.7" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "schnorrkel", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + +[[package]] +name = "substrate-fixed" +version = "0.5.9" +source = "git+https://github.com/encointer/substrate-fixed#879c58bcc6fd676a74315dcd38b598f28708b0b5" +dependencies = [ + "parity-scale-codec", + "scale-info", + "substrate-typenum", +] + +[[package]] +name = "substrate-typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f0091e93c2c75b233ae39424c52cb8a662c0811fb68add149e20e5d7e8a788" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "substrate-wasm-builder" +version = "17.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "build-helper", + "cargo_metadata", + "console", + "filetime", + "parity-wasm", + "polkavm-linker", + "sp-maybe-compressed-blob", + "strum 0.26.2", + "tempfile", + "toml", + "walkdir", + "wasm-opt", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.9", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.5", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trie-db" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" +dependencies = [ + "hash-db", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" +dependencies = [ + "hash-db", +] + +[[package]] +name = "tt-call" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.7", + "rand", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "w3f-bls" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-serialize-derive", + "arrayref", + "constcat", + "digest 0.10.7", + "rand", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "sha2 0.10.8", + "sha3", + "thiserror", + "zeroize", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-opt" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" +dependencies = [ + "anyhow", + "libc", + "strum 0.24.1", + "strum_macros 0.24.3", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", +] + +[[package]] +name = "wide" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xcm-fee-payment-runtime-api" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "xcm-primitives" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#509c4f44bb49dab0d3dda640a936ac047e109972" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "xcm-primitives" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3100#6750bb31fb0adac8f1020154a641f376b3b434b8" +dependencies = [ + "cumulus-primitives-core", + "ethereum", + "ethereum-types", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "impl-trait-for-tuples", + "log", + "orml-traits", + "pallet-staking", + "parity-scale-codec", + "polkadot-runtime-common", + "scale-info", + "serde", + "sha3", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[package]] +name = "xcm-procedural" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#08968b280245b53ce790f9234289960ace6bbaee" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/tracing/3100/Cargo.toml b/tracing/3100/Cargo.toml new file mode 100644 index 00000000..4c605db6 --- /dev/null +++ b/tracing/3100/Cargo.toml @@ -0,0 +1,454 @@ +[workspace] +members = [ + "runtime/moonbase", + "runtime/moonbeam", + "runtime/moonriver", +] +resolver = "2" + +[workspace.package] +authors = ["PureStake"] +repository = "https://github.com/PureStake/moonbeam" + +[workspace.dependencies] +# Dependencies are split into 2 groups: wasm and client. +# - "wasm" dependencies requires to be no_std compatible, which often requires +# `default-features = false`. When used in a client-side crate the "std" feature should be enabled +# there if it exists. +# - "client" dependencies are only used in the client, and thus don't need to be no_std compatible. + +# Moonbeam (wasm) +account = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +evm-tracing-events = { path = "shared/primitives/rpc/evm-tracing-events", default-features = false , features = ["runtime-1600"] } +moonbeam-core-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-primitives-ext = { path = "shared/primitives/ext", default-features = false } +moonbeam-rpc-primitives-debug = { path = "shared/primitives/rpc/debug", default-features = false, features = [ + "runtime-3000", +] } +moonbeam-rpc-primitives-txpool = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +storage-proof-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } + +moonbeam-evm-tracer = { path = "shared/runtime/evm_tracer", default-features = false } +moonbeam-relay-encoder = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-runtime-common = { path = "runtime/common", default-features = false } + +moonbeam-xcm-benchmarks = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-asset-manager = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-erc20-xcm-bridge = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-ethereum-xcm = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-moonbeam-foreign-assets = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-moonbeam-lazy-migrations = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } + +pallet-evm-precompile-author-mapping = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-balances-erc20 = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-batch = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-call-permit = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-collective = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-conviction-voting = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-crowdloan-rewards = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-gmp = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-identity = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-parachain-staking = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-preimage = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-proxy = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-randomness = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-referenda = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-registry = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-relay-encoder = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-relay-verifier = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-xcm-transactor = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-xcm-utils = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-xtokens = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompile-p256verify = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-evm-precompileset-assets-erc20 = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-moonbeam-orbiters = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-parachain-staking = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-precompile-benchmarks = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-proxy-genesis-companion = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +pallet-xcm-transactor = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +precompile-foreign-asset-migrator = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +xcm-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } + +pallet-crowdloan-rewards = { git = "https://github.com/moonbeam-foundation/crowdloan-rewards", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Moonbeam (client) +moonbeam-cli = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-cli-opt = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-service = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } + +manual-xcm-rpc = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-client-evm-tracing = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-finality-rpc = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-core-debug = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-core-trace = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-core-txpool = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-core-types = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-debug = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-trace = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-rpc-txpool = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } +moonbeam-vrf = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3100" } + +moonbase-runtime = { path = "runtime/moonbase" } +moonbeam-runtime = { path = "runtime/moonbeam" } +moonriver-runtime = { path = "runtime/moonriver" } + +frame-benchmarking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-executive = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-support = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system-benchmarking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system-rpc-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-try-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-assets = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-balances = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-collective = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-conviction-voting = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-identity = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-message-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-multisig = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-preimage = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-proxy = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-referenda = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-root-testing = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-scheduler = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-society = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-staking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-sudo = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-transaction-payment = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-treasury = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-utility = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-whitelist = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parity-scale-codec = { version = "3.2.2", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.0", default-features = false, features = [ + "derive", +] } +sp-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-application-crypto = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-block-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-consensus-babe = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-consensus-slots = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-core = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-debug-derive = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-externalities = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-inherents = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-io = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-keystore = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-offchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-runtime-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-session = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-std = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-state-machine = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-transaction-pool = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-trie = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-version = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-weights = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-genesis-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false } + +# Substrate (client) +frame-benchmarking-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +pallet-transaction-payment-rpc = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-basic-authorship = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-block-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-chain-spec = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-client-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-client-db = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus-grandpa = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus-manual-seal = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-executor = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-informant = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network-sync = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-offchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-rpc = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-rpc-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-sysinfo = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-telemetry = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-tracing = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-transaction-pool = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-transaction-pool-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-blockchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-consensus = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-storage = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-wasm-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-build-script-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-frame-rpc-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-prometheus-endpoint = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-client = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-runtime-client = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-wasm-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Frontier (wasm) + +ethereum = { version = "0.15.0", default-features = false, features = [ + "with-codec", +] } +ethereum-types = { version = "0.14", default-features = false } +evm = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +evm-gasometer = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +evm-runtime = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-ethereum = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-evm = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-rpc = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-self-contained = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-ethereum = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "forbid-evm-reentrancy", +] } +pallet-evm = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "forbid-evm-reentrancy", +] } +pallet-evm-chain-id = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-blake2 = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-bn128 = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-dispatch = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-modexp = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-sha3fips = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-storage-cleaner = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +precompile-utils = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +precompile-utils-macro = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + + +# Frontier (client) +fc-consensus = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-db = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-api = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-mapping-sync = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-rpc = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", features = [ + "rpc-binary-search-estimate", +] } +fc-rpc-core = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-storage = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fp-consensus = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fp-storage = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } + +# Cumulus (wasm) + +cumulus-pallet-dmp-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-pallet-parachain-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "parameterized-consensus-hook", +] } +cumulus-pallet-xcm = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-pallet-xcmp-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-core = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-parachain-inherent = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-test-relay-sproof-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parachain-info = { package = "staging-parachain-info", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parachains-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Cumulus (client) +cumulus-client-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-collator = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-proposer = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-relay-chain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-network = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-parachain-inherent = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-inprocess-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-minimal-node = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-rpc-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Polkadot / XCM (wasm) +orml-traits = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +orml-xcm-support = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +orml-xtokens = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-xcm = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-xcm-benchmarks = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-core-primitives = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-parachain = { package = "polkadot-parachain-primitives", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-runtime-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-runtime-parachains = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm = { package = "staging-xcm", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-fee-payment-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Polkadot / XCM (client) +#kusama-runtime = { package = "staging-kusama-runtime", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-primitives = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +#polkadot-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +rococo-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +westend-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +xcm-simulator = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Moonkit (wasm) +async-backing-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +moonkit-xcm-primitives = { package = "xcm-primitives", git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +nimbus-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-async-backing = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-inherent = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-mapping = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-slot-filter = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-emergency-para-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-maintenance-mode = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-migrations = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-randomness = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-relay-storage-roots = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +session-keys-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Moonkit (client) +nimbus-consensus = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0" } + +# Other (wasm) +async-trait = { version = "0.1.42" } +blake2-rfc = { version = "0.2.18", default-features = false } +derive_more = "0.99" +environmental = { version = "1.1.2", default-features = false } +frame-metadata = { version = "16.0.0", default-features = false, features = [ + "current", +] } +hex = { version = "0.4.3", default-features = false } +hex-literal = { version = "0.3.4" } +impl-serde = { version = "0.3.1", default-features = false } +impl-trait-for-tuples = "0.2.1" +libsecp256k1 = { version = "0.7", default-features = false } +log = { version = "0.4", default-features = false } +num_enum = { version = "0.5.3", default-features = false } +paste = "1.0.6" +rlp = { version = "0.5", default-features = false } +rustc-hex = { version = "2.0.1", default-features = false } +serde = { version = "1.0.101", default-features = false } +sha3 = { version = "0.10", default-features = false } +slices = "0.2.0" +smallvec = "1.8.0" +strum = { version = "0.24", default-features = false, features = ["derive"] } +strum_macros = "0.24" +p256 = { version = "0.13.2", default-features = false, features = [ + "ecdsa", +] } + +# Other (client) + +assert_cmd = "2.0.10" +async-io = "1.3" +bip32 = { version = "0.5.1", default-features = false, features = ["bip39"] } +clap = { version = "4.0.9", features = ["derive"] } +clap-num = "=1.1.1" +exit-future = "0.2" +flume = "0.10.9" +futures = { version = "0.3.21" } +jsonrpsee = { version = "0.22.5", default-features = false } +maplit = "1.0.2" +nix = "0.23" +parking_lot = "0.12.0" +primitive-types = "0.12.0" +prometheus = { version = "0.13.0", default-features = false } +rand = "0.8.5" +serde_json = { version = "1.0" } +similar-asserts = "1.1.0" +tempfile = "3.2.0" +tiny-bip39 = { version = "0.8", default-features = false } +schnorrkel = { version = "0.11.4", default-features = false, features = [ + "preaudit_deprecated", +] } +tokio = { version = "1.36" } +tracing = "0.1.34" +tracing-core = "0.1.29" +trie-root = "0.15.2" +url = "2.2.2" + +# The list of dependencies below (which can be both direct and indirect dependencies) are crates +# that are suspected to be CPU-intensive, and that are unlikely to require debugging (as some of +# their debug info might be missing) or to require to be frequently recompiled. We compile these +# dependencies with `opt-level=3` even in "dev" mode in order to make "dev" mode more usable. +# The majority of these crates are cryptographic libraries. +# +# Note that this does **not** affect crates that depend on Moonbeam. In other words, if you add +# a dependency on Moonbeam, you have to copy-paste this list in your own `Cargo.toml` (assuming +# that you want the same list). This list is only relevant when running `cargo build` from within +# the Moonbeam workspace. +# +# If you see an error mentioning "profile package spec ... did not match any packages", it +# probably concerns this list. +# +# This list is ordered alphabetically. +[profile.dev.package] +blake2 = { opt-level = 3 } +blake2b_simd = { opt-level = 3 } +chacha20poly1305 = { opt-level = 3 } +cranelift-codegen = { opt-level = 3 } +cranelift-wasm = { opt-level = 3 } +crc32fast = { opt-level = 3 } +crossbeam-deque = { opt-level = 3 } +crypto-mac = { opt-level = 3 } +curve25519-dalek = { opt-level = 3 } +ed25519-zebra = { opt-level = 3 } +flate2 = { opt-level = 3 } +futures-channel = { opt-level = 3 } +hash-db = { opt-level = 3 } +hashbrown = { opt-level = 3 } +hmac = { opt-level = 3 } +httparse = { opt-level = 3 } +integer-sqrt = { opt-level = 3 } +k256 = { opt-level = 3 } +keccak = { opt-level = 3 } +libm = { opt-level = 3 } +librocksdb-sys = { opt-level = 3 } +libsecp256k1 = { opt-level = 3 } +libz-sys = { opt-level = 3 } +mio = { opt-level = 3 } +nalgebra = { opt-level = 3 } +num-bigint = { opt-level = 3 } +parking_lot = { opt-level = 3 } +parking_lot_core = { opt-level = 3 } +percent-encoding = { opt-level = 3 } +primitive-types = { opt-level = 3 } +ring = { opt-level = 3 } +rustls = { opt-level = 3 } +secp256k1 = { opt-level = 3 } +sha2 = { opt-level = 3 } +sha3 = { opt-level = 3 } +smallvec = { opt-level = 3 } +snow = { opt-level = 3 } +twox-hash = { opt-level = 3 } +uint = { opt-level = 3 } +wasmi = { opt-level = 3 } +x25519-dalek = { opt-level = 3 } +yamux = { opt-level = 3 } +zeroize = { opt-level = 3 } + +# make sure dev builds with backtrace do +# not slow us down +[profile.dev.package.backtrace] +inherits = "release" + +[profile.production] +codegen-units = 1 +incremental = false +inherits = "release" +lto = true + +[profile.release] +debug-assertions = true # Enable debug-assert! for non-production profiles +opt-level = 3 +# Moonbeam runtime requires unwinding. +panic = "unwind" + +[profile.testnet] +debug = 1 # debug symbols are useful for profilers +debug-assertions = true # Enable debug-assert! for non-production profiles +inherits = "release" +overflow-checks = true + +[patch."https://github.com/paritytech/polkadot-sdk"] +sp-crypto-ec-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } diff --git a/tracing/3100/runtime/common/Cargo.toml b/tracing/3100/runtime/common/Cargo.toml new file mode 100644 index 00000000..292ba44b --- /dev/null +++ b/tracing/3100/runtime/common/Cargo.toml @@ -0,0 +1,154 @@ +[package] +authors = { workspace = true } +description = "Common code shared between runtimes" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbeam-runtime-common" +version = "0.8.0-dev" + +[dependencies] +hex-literal = "0.3.4" +impl-trait-for-tuples = "0.2.1" +log = "0.4" + +# Moonbeam +moonbeam-core-primitives = { workspace = true } +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-randomness = { workspace = true } +pallet-relay-storage-roots = { workspace = true } +pallet-xcm-transactor = { workspace = true } +xcm-primitives = { workspace = true } + +# Substrate +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +frame-benchmarking = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +pallet-collective = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-identity = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +pallet-xcm = { workspace = true } +sp-api = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-genesis-builder = { workspace = true } +frame-try-runtime = { workspace = true } + +# Frontier +fp-ethereum = { workspace = true } +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-chain-id = { workspace = true } +precompile-utils = { workspace = true } + +# Moonkit +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } + +# Polkadot +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Parity +parity-scale-codec = { workspace = true } + +account = { workspace = true } + +[features] +std = [ + "cumulus-pallet-parachain-system/std", + "fp-ethereum/std", + "fp-evm/std", + "frame-support/std", + "moonbeam-core-primitives/std", + "pallet-asset-manager/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-ethereum-xcm/std", + "pallet-evm/std", + "pallet-migrations/std", + "pallet-parachain-staking/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-scheduler/std", + "pallet-xcm-transactor/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-identity/std", + "parity-scale-codec/std", + "precompile-utils/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", + "sp-genesis-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm/std", + "account/std", +] +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", +] +try-runtime = ["cumulus-pallet-parachain-system/try-runtime", "frame-support/try-runtime", "pallet-migrations/try-runtime"] diff --git a/tracing/3100/runtime/common/src/apis.rs b/tracing/3100/runtime/common/src/apis.rs new file mode 100644 index 00000000..38912cb7 --- /dev/null +++ b/tracing/3100/runtime/common/src/apis.rs @@ -0,0 +1,1178 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_runtime_apis_plus_common { + {$($custom:tt)*} => { + + #[cfg(feature = "evm-tracing")] + // Helper function to replay the "on_idle" hook for all pallets, we need this for + // evm-tracing because some ethereum-xcm transactions might be executed at on_idle. + // + // We need to make sure that we replay on_idle exactly the same way as the + // original block execution, but unfortunatly frame executive diosn't provide a function + // to replay only on_idle, so we need to copy here some code inside frame executive. + fn replay_on_idle() { + use frame_system::pallet_prelude::BlockNumberFor; + use frame_support::traits::OnIdle; + + let weight = >::block_weight(); + let max_weight = < + ::BlockWeights as + frame_support::traits::Get<_> + >::get().max_block; + let remaining_weight = max_weight.saturating_sub(weight.total()); + if remaining_weight.all_gt(Weight::zero()) { + let _ = >>::on_idle( + >::block_number(), + remaining_weight, + ); + } + } + + impl_runtime_apis! { + $($custom)* + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics( + data: sp_inherents::InherentData, + ) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn decode_session_keys( + encoded: Vec, + ) -> Option, sp_core::crypto::KeyTypeId)>> { + opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + } + + fn generate_session_keys(seed: Option>) -> Vec { + opaque::SessionKeys::generate(seed) + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn build_state(config: Vec) -> sp_genesis_builder::Result { + frame_support::genesis_builder_helper::build_state::(config) + } + + fn get_preset(id: &Option) -> Option> { + frame_support::genesis_builder_helper::get_preset::(id, |_| None) + } + + fn preset_names() -> Vec { + vec![] + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl moonbeam_rpc_primitives_debug::DebugRuntimeApi for Runtime { + fn trace_transaction( + extrinsics: Vec<::Extrinsic>, + traced_transaction: &EthereumTransaction, + header: &::Header, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + use xcm_primitives::{ + ETHEREUM_XCM_TRACING_STORAGE_KEY, + EthereumXcmTracingStatus + }; + use frame_support::storage::unhashed; + use frame_system::pallet_prelude::BlockNumberFor; + + // Tell the CallDispatcher we are tracing a specific Transaction. + unhashed::put::( + ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::Transaction(traced_transaction.hash()), + ); + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + // After pallet message queue was introduced, this must be done only after + // enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY + // in the storage + Executive::initialize_block(header); + + // Apply the a subset of extrinsics: all the substrate-specific or ethereum + // transactions that preceded the requested transaction. + for ext in extrinsics.into_iter() { + let _ = match &ext.0.function { + RuntimeCall::Ethereum(transact { transaction }) => { + if transaction == traced_transaction { + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + return Ok(()); + } else { + Executive::apply_extrinsic(ext) + } + } + _ => Executive::apply_extrinsic(ext), + }; + if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + return Ok(()); + } + } + + if let Some(EthereumXcmTracingStatus::Transaction(_)) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // If the transaction was not found, it might be + // an eth-xcm transaction that was executed at on_idle + replay_on_idle(); + } + + if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // The transaction was found + Ok(()) + } else { + // The transaction was not-found + Err(sp_runtime::DispatchError::Other( + "Failed to find Ethereum transaction among the extrinsics.", + )) + } + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + + fn trace_block( + extrinsics: Vec<::Extrinsic>, + known_transactions: Vec, + header: &::Header, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + use frame_system::pallet_prelude::BlockNumberFor; + use xcm_primitives::EthereumXcmTracingStatus; + + // Tell the CallDispatcher we are tracing a full Block. + frame_support::storage::unhashed::put::( + xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::Block, + ); + + let mut config = ::config().clone(); + config.estimate = true; + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + // After pallet message queue was introduced, this must be done only after + // enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY + // in the storage + Executive::initialize_block(header); + + // Apply all extrinsics. Ethereum extrinsics are traced. + for ext in extrinsics.into_iter() { + match &ext.0.function { + RuntimeCall::Ethereum(transact { transaction }) => { + if known_transactions.contains(&transaction.hash()) { + // Each known extrinsic is a new call stack. + EvmTracer::emit_new(); + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + } else { + let _ = Executive::apply_extrinsic(ext); + } + } + _ => { + let _ = Executive::apply_extrinsic(ext); + } + }; + } + + // Replay on_idle + // Some XCM messages with eth-xcm transaction might be executed at on_idle + replay_on_idle(); + + Ok(()) + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + + fn trace_call( + header: &::Header, + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Option)>>, + ) -> Result<(), sp_runtime::DispatchError> { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + Executive::initialize_block(header); + + EvmTracer::new().trace(|| { + let is_transactional = false; + let validate = true; + let without_base_extrinsic_weight = true; + + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + let _ = ::Runner::call( + from, + to, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + ::config(), + ); + }); + Ok(()) + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + } + + impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi for Runtime { + fn extrinsic_filter( + xts_ready: Vec<::Extrinsic>, + xts_future: Vec<::Extrinsic>, + ) -> TxPoolResponse { + TxPoolResponse { + ready: xts_ready + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + future: xts_future + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + } + } + } + + impl fp_rpc::EthereumRuntimeRPCApi for Runtime { + fn chain_id() -> u64 { + ::ChainId::get() + } + + fn account_basic(address: H160) -> EVMAccount { + let (account, _) = EVM::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(address) + } + + fn author() -> H160 { + >::find_author() + } + + fn storage_at(address: H160, index: U256) -> H256 { + let mut tmp = [0u8; 32]; + index.to_big_endian(&mut tmp); + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) + } + + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + let mut estimated_transaction_len = data.len() + + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 190; + + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + gas_limit.low_u64() + }; + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + #[allow(clippy::or_fun_call)] // suggestion not helpful here + ::Runner::create( + from, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option>, + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get(), + ) + } + + fn extrinsic_filter( + xts: Vec<::Extrinsic>, + ) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None + }).collect::>() + } + + fn elasticity() -> Option { + None + } + + fn gas_limit_multiplier_support() {} + + fn pending_block( + xts: Vec<::Extrinsic> + ) -> ( + Option, Option> + ) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } + + Ethereum::on_finalize(System::block_number() + 1); + + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn initialize_pending_block(header: &::Header) { + pallet_randomness::vrf::using_fake_vrf(|| { + let _ = Executive::initialize_block(header); + }) + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction( + transaction: pallet_ethereum::Transaction + ) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl nimbus_primitives::NimbusApi for Runtime { + fn can_author( + author: nimbus_primitives::NimbusId, + slot: u32, + parent_header: &::Header + ) -> bool { + use pallet_parachain_staking::Config as PalletParachainStakingConfig; + + let block_number = parent_header.number + 1; + + // The Moonbeam runtimes use an entropy source that needs to do some accounting + // work during block initialization. Therefore we initialize it here to match + // the state it will be in when the next block is being executed. + use frame_support::traits::OnInitialize; + System::initialize( + &block_number, + &parent_header.hash(), + &parent_header.digest, + ); + + // Because the staking solution calculates the next staking set at the beginning + // of the first block in the new round, the only way to accurately predict the + // authors is to compute the selection during prediction. + if pallet_parachain_staking::Pallet::::round() + .should_update(block_number) { + // get author account id + use nimbus_primitives::AccountLookup; + let author_account_id = if let Some(account) = + pallet_author_mapping::Pallet::::lookup_account(&author) { + account + } else { + // return false if author mapping not registered like in can_author impl + return false + }; + let candidates = pallet_parachain_staking::Pallet::::compute_top_candidates(); + if candidates.is_empty() { + // If there are zero selected candidates, we use the same eligibility + // as the previous round + return AuthorInherent::can_author(&author, &slot); + } + + // predict eligibility post-selection by computing selection results now + let (eligible, _) = + pallet_author_slot_filter::compute_pseudo_random_subset::( + candidates, + &slot + ); + eligible.contains(&author_account_id) + } else { + AuthorInherent::can_author(&author, &slot) + } + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info( + header: &::Header + ) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl session_keys_primitives::VrfApi for Runtime { + fn get_last_vrf_output() -> Option<::Hash> { + // TODO: remove in future runtime upgrade along with storage item + if pallet_randomness::Pallet::::not_first_block().is_none() { + return None; + } + pallet_randomness::Pallet::::local_vrf_output() + } + fn vrf_key_lookup( + nimbus_id: nimbus_primitives::NimbusId + ) -> Option { + use session_keys_primitives::KeysLookup; + AuthorMapping::lookup_keys(&nimbus_id) + } + } + + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets( + xcm_version: xcm::Version + ) -> Result, XcmPaymentApiError> { + if !matches!(xcm_version, 3) { + return Err(XcmPaymentApiError::UnhandledXcmVersion); + } + + let self_reserve_location: Location = Location::try_from(xcm_config::SelfReserve::get()) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + Ok([VersionedAssetId::V3(XcmAssetId::from(self_reserve_location))] + .into_iter() + .chain( + pallet_asset_manager::AssetTypeId::::iter_keys().filter_map(|asset_location| { + if !AssetManager::payment_is_supported(asset_location.clone()) { + return None; + } + + let location: Option = asset_location.into(); + if let Some(loc) = location { + return Some(VersionedAssetId::V3(loc.into())) + } + None + }) + ) + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee( + weight: Weight, asset: VersionedAssetId + ) -> Result { + let self_reserve_location: Location = Location::try_from(xcm_config::SelfReserve::get()) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + let local_asset = VersionedAssetId::V3(XcmAssetId::from(self_reserve_location)); + let asset = asset + .into_version(3) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if asset == local_asset { + Ok(TransactionPayment::weight_to_fee(weight)) + }else { + let asset_v3: XcmAssetId = asset.try_into() + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if let XcmAssetId::Concrete(asset_location) = asset_v3 { + let asset_type: AssetType = AssetType::from(asset_location); + if !AssetManager::payment_is_supported(asset_type.clone()) { + return Err(XcmPaymentApiError::AssetNotFound); + } + + let units_per_sec = AssetManager::get_units_per_second(asset_type); + if let None = units_per_sec { + return Err(XcmPaymentApiError::WeightNotComputable); + } + + let final_asset_fee = units_per_sec + .unwrap_or_default() + .saturating_mul(weight.ref_time() as u128) + / (WEIGHT_REF_TIME_PER_SECOND as u128); + + return Ok(final_asset_fee) + } + Err(XcmPaymentApiError::AssetNotFound) + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees( + destination: VersionedLocation, message: VersionedXcm<()> + ) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use moonbeam_xcm_benchmarks::generic::benchmarking as MoonbeamXcmBenchmarks; + use frame_support::traits::StorageInfoTrait; + use MoonbeamXcmBenchmarks::XcmGenericBenchmarks as MoonbeamXcmGenericBench; + + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + + return (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig, + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{add_benchmark, BenchmarkBatch, Benchmarking}; + use frame_support::traits::TrackedStorageKey; + use cumulus_primitives_core::ParaId; + + use xcm::latest::prelude::{ + GeneralIndex, Junction, Junctions, Location, Response, NetworkId, AssetId, + Assets as XcmAssets, Fungible, Asset, ParentThen, Parachain, Parent + }; + use xcm_config::SelfReserve; + use frame_benchmarking::BenchmarkError; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + impl moonbeam_xcm_benchmarks::Config for Runtime {} + impl moonbeam_xcm_benchmarks::generic::Config for Runtime {} + + use pallet_asset_manager::Config as PalletAssetManagerConfig; + + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + parameter_types! { + pub const RandomParaId: ParaId = ParaId::new(43211234); + } + + pub struct TestDeliveryHelper; + impl xcm_builder::EnsureDelivery for TestDeliveryHelper { + fn ensure_successful_delivery( + origin_ref: &Location, + _dest: &Location, + _fee_reason: xcm_executor::traits::FeeReason, + ) -> (Option, Option) { + use xcm_executor::traits::ConvertLocation; + let account = xcm_config::LocationToH160::convert_location(origin_ref) + .expect("Invalid location"); + // Give the existential deposit at least + let balance = ExistentialDeposit::get(); + let _ = >:: + make_free_balance_be(&account.into(), balance); + + (None, None) + } + } + + impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = TestDeliveryHelper; + + fn get_asset() -> Asset { + Asset { + id: AssetId(SelfReserve::get()), + fun: Fungible(ExistentialDeposit::get()), + } + } + + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(Asset, Location)> { + None + } + + fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { + use xcm_config::SelfReserve; + + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + RandomParaId::get().into() + ); + + Some(( + Asset { + fun: Fungible(ExistentialDeposit::get()), + id: AssetId(SelfReserve::get().into()) + }, + // Moonbeam can reserve transfer native token to + // some random parachain. + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), + )) + } + + fn set_up_complex_asset_transfer( + ) -> Option<(XcmAssets, u32, Location, Box)> { + use xcm_config::SelfReserve; + + let destination: xcm::v4::Location = Parent.into(); + + let fee_amount: u128 = ::ExistentialDeposit::get(); + let fee_asset: Asset = (SelfReserve::get(), fee_amount).into(); + + // Give some multiple of transferred amount + let balance = fee_amount * 1000; + let who = frame_benchmarking::whitelisted_caller(); + let _ = + >::make_free_balance_be(&who, balance); + + // verify initial balance + assert_eq!(Balances::free_balance(&who), balance); + + // set up local asset + let asset_amount: u128 = 10u128; + let initial_asset_amount: u128 = asset_amount * 10; + + let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< + Runtime, + () + >(true, initial_asset_amount); + let transfer_asset: Asset = (SelfReserve::get(), asset_amount).into(); + + let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into(); + let fee_index: u32 = 0; + + let verify: Box = Box::new(move || { + // verify balance after transfer, decreased by + // transferred amount (and delivery fees) + assert!(Balances::free_balance(&who) <= balance - fee_amount); + }); + + Some((assets, fee_index, destination, verify)) + } + } + + impl pallet_xcm_benchmarks::Config for Runtime { + type XcmConfig = xcm_config::XcmExecutorConfig; + type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = (); + fn valid_destination() -> Result { + Ok(Location::parent()) + } + fn worst_case_holding(_depositable_count: u32) -> XcmAssets { + // 100 fungibles + const HOLDING_FUNGIBLES: u32 = 100; + let fungibles_amount: u128 = 100; + let assets = (0..HOLDING_FUNGIBLES).map(|i| { + let location: Location = GeneralIndex(i as u128).into(); + Asset { + id: AssetId(location), + fun: Fungible(fungibles_amount * i as u128), + } + .into() + }) + .chain( + core::iter::once( + Asset { + id: AssetId(Location::parent()), + fun: Fungible(u128::MAX) + } + ) + ) + .collect::>(); + + + for (i, asset) in assets.iter().enumerate() { + if let Asset { + id: AssetId(location), + fun: Fungible(_) + } = asset { + ::AssetId, + ::ForeignAssetType> + >::set_asset_type_asset_id( + location.clone().try_into().expect("convert to v3"), + i as u128 + ); + // set 1-1 + ::ForeignAssetType> + >::set_units_per_second( + location.clone().try_into().expect("convert to v3"), + 1_000_000_000_000u128 + ); + } + } + assets.into() + } + } + + impl pallet_xcm_benchmarks::generic::Config for Runtime { + type RuntimeCall = RuntimeCall; + type TransactAsset = Balances; + + fn worst_case_response() -> (u64, Response) { + (0u64, Response::Version(Default::default())) + } + + fn worst_case_asset_exchange() + -> Result<(XcmAssets, XcmAssets), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn universal_alias() -> Result<(Location, Junction), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn export_message_origin_and_destination() + -> Result<(Location, NetworkId, Junctions), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn transact_origin_and_runtime_call() + -> Result<(Location, RuntimeCall), BenchmarkError> { + Ok((Location::parent(), frame_system::Call::remark_with_event { + remark: vec![] + }.into())) + } + + fn subscribe_origin() -> Result { + Ok(Location::parent()) + } + + fn claimable_asset() + -> Result<(Location, Location, XcmAssets), BenchmarkError> { + let origin = Location::parent(); + let assets: XcmAssets = (AssetId(Location::parent()), 1_000u128) + .into(); + let ticket = Location { parents: 0, interior: [].into() /* Here */ }; + Ok((origin, ticket, assets)) + } + + fn fee_asset() -> Result { + Err(BenchmarkError::Skip) + } + + fn unlockable_asset() + -> Result<(Location, Location, Asset), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn alias_origin() -> Result<(Location, Location), BenchmarkError> { + Err(BenchmarkError::Skip) + } + } + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "02a5c1b19ab7a04f536c519aca4983ac") + .to_vec().into(), + // Total Issuance + hex_literal::hex!( "c2261276cc9d1f8598ea4b6a74b15c2f" + "57c875e4cff74148e4628f264b974c80") + .to_vec().into(), + // Execution Phase + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "ff553b5a9862a516939d82b3d3d8661a") + .to_vec().into(), + // Event Count + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "0a98fdbe9ce6c55837576c60c7af3850") + .to_vec().into(), + // System Events + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "80d41e5e16056765bc8461851072c9d7") + .to_vec().into(), + // System BlockWeight + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "34abf5cb34d6244378cddbf18e849d96") + .to_vec().into(), + // ParachainStaking Round + hex_literal::hex!( "a686a3043d0adcf2fa655e57bc595a78" + "13792e785168f725b60e2969c7fc2552") + .to_vec().into(), + // Treasury Account (py/trsry) + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "b99d880ec681799c0cf30e8886371da9" + "7be2919ac397ba499ea5e57132180ec6" + "6d6f646c70792f747273727900000000" + "00000000" + ).to_vec().into(), + // Treasury Account (pc/trsry) + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "b99d880ec681799c0cf30e8886371da9" + "7be2919ac397ba499ea5e57132180ec6" + "6d6f646c70632f747273727900000000" + "00000000" + ).to_vec().into(), + // ParachainInfo ParachainId + hex_literal::hex!( "0d715f2646c8f85767b5d2764bb27826" + "04a74d81251e398fd8a0a4d55023bb3f") + .to_vec().into(), + + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + add_benchmarks!(params, batches); + + if batches.is_empty() { + return Err("Benchmark not found for this pallet.".into()); + } + Ok(batches) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade()"); + // NOTE: intentional expect: we don't want to propagate the error backwards, + // and want to have a backtrace here. If any of the pre/post migration checks + // fail, we shall stop right here and right now. + let weight = Executive::try_runtime_upgrade(checks) + .expect("runtime upgrade logic *must* be infallible"); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + log::info!( + "try-runtime: executing block {:?} / root checks: {:?} / try-state-select: {:?}", + block.header.hash(), + state_root_check, + select, + ); + // NOTE: intentional unwrap: we don't want to propagate the error backwards, + // and want to have a backtrace here. + Executive::try_execute_block( + block, + state_root_check, + signature_check, + select, + ).expect("execute-block failed") + } + } + } + }; +} diff --git a/tracing/3100/runtime/common/src/benchmarking.rs b/tracing/3100/runtime/common/src/benchmarking.rs new file mode 100644 index 00000000..b6985b5b --- /dev/null +++ b/tracing/3100/runtime/common/src/benchmarking.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use account::AccountId20; +use pallet_treasury::ArgumentsFactory; + +pub struct BenchmarkHelper; + +impl ArgumentsFactory<(), AccountId20> for BenchmarkHelper { + fn create_asset_kind(_seed: u32) -> () { + () + } + + fn create_beneficiary(seed: [u8; 32]) -> AccountId20 { + AccountId20::from(seed) + } +} diff --git a/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call.rs b/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call.rs new file mode 100644 index 00000000..112c457c --- /dev/null +++ b/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call.rs @@ -0,0 +1,51 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_moonbeam_xcm_call { + {} => { + + pub struct MoonbeamCall; + impl CallDispatcher for MoonbeamCall { + fn dispatch( + call: RuntimeCall, + origin: RuntimeOrigin, + ) -> Result< + PostDispatchInfoOf, + DispatchErrorWithPostInfo> + > { + if let Ok(raw_origin) = TryInto::>::try_into(origin.clone().caller) { + match (call.clone(), raw_origin) { + ( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { .. }) | + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact_through_proxy { .. }), + RawOrigin::Signed(account_id) + ) => { + return RuntimeCall::dispatch( + call, + pallet_ethereum_xcm::Origin::XcmEthereumTransaction( + account_id.into() + ).into() + ); + }, + _ => {} + } + } + RuntimeCall::dispatch(call, origin) + } + } + } +} diff --git a/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs b/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs new file mode 100644 index 00000000..ffddb3b8 --- /dev/null +++ b/tracing/3100/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_moonbeam_xcm_call_tracing { + {} => { + + type CallResult = + Result< + PostDispatchInfoOf, + DispatchErrorWithPostInfo> + >; + + pub struct MoonbeamCall; + impl CallDispatcher for MoonbeamCall { + fn dispatch( + call: RuntimeCall, + origin: RuntimeOrigin, + ) -> CallResult { + if let Ok(raw_origin) = TryInto::>::try_into(origin.clone().caller) { + match (call.clone(), raw_origin) { + ( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { xcm_transaction }) | + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact_through_proxy { + xcm_transaction, .. + }), + RawOrigin::Signed(account_id) + ) => { + use crate::EthereumXcm; + use moonbeam_evm_tracer::tracer::EvmTracer; + use xcm_primitives::{ + XcmToEthereum, + EthereumXcmTracingStatus, + ETHEREUM_XCM_TRACING_STORAGE_KEY + }; + use frame_support::storage::unhashed; + use frame_support::traits::Get; + + let dispatch_call = || { + RuntimeCall::dispatch( + call, + pallet_ethereum_xcm::Origin::XcmEthereumTransaction( + account_id.into() + ).into() + ) + }; + + return match unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // This runtime instance is used for tracing. + Some(tracing_status) => match tracing_status { + // Tracing a block, all calls are done using environmental. + EthereumXcmTracingStatus::Block => { + // Each known extrinsic is a new call stack. + EvmTracer::emit_new(); + let mut res: Option = None; + EvmTracer::new().trace(|| { + res = Some(dispatch_call()); + }); + res.expect("Invalid dispatch result") + }, + // Tracing a transaction, the one matching the trace request + // is done using environmental, the rest dispatched normally. + EthereumXcmTracingStatus::Transaction(traced_transaction_hash) => { + let transaction_hash = xcm_transaction.into_transaction_v2( + EthereumXcm::nonce(), + ::ChainId::get(), + false + ) + .expect("Invalid transaction conversion") + .hash(); + if transaction_hash == traced_transaction_hash { + let mut res: Option = None; + EvmTracer::new().trace(|| { + res = Some(dispatch_call()); + }); + // Tracing runtime work is done, just signal instance exit. + unhashed::put::( + xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::TransactionExited, + ); + return res.expect("Invalid dispatch result"); + } + dispatch_call() + }, + // Tracing a transaction that has already been found and + // executed. There's no need to dispatch the rest of the + // calls. + EthereumXcmTracingStatus::TransactionExited => Ok(crate::PostDispatchInfo { + actual_weight: None, + pays_fee: frame_support::pallet_prelude::Pays::No, + }), + }, + // This runtime instance is importing a block. + None => dispatch_call() + }; + }, + _ => {} + } + } + RuntimeCall::dispatch(call, origin) + } + } + } +} diff --git a/tracing/3100/runtime/common/src/impl_on_charge_evm_transaction.rs b/tracing/3100/runtime/common/src/impl_on_charge_evm_transaction.rs new file mode 100644 index 00000000..baa4777e --- /dev/null +++ b/tracing/3100/runtime/common/src/impl_on_charge_evm_transaction.rs @@ -0,0 +1,62 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_on_charge_evm_transaction { + {} => { + type FungibleAccountId = ::AccountId; + + type BalanceFor = + <::Currency as Inspect>>::Balance; + + pub struct OnChargeEVMTransaction(sp_std::marker::PhantomData); + + impl OnChargeEVMTransactionT for OnChargeEVMTransaction + where + T: pallet_evm::Config, + T::Currency: Balanced, + OU: OnUnbalanced>, + U256: UniqueSaturatedInto> + { + type LiquidityInfo = Option>; + + fn withdraw_fee(who: &H160, fee: U256) -> Result> { + EVMFungibleAdapter::<::Currency, ()>::withdraw_fee(who, fee) + } + + fn can_withdraw(who: &H160, amount: U256) -> Result<(), pallet_evm::Error> { + EVMFungibleAdapter::<::Currency, ()>::can_withdraw(who, amount) + } + + fn correct_and_deposit_fee( + who: &H160, + corrected_fee: U256, + base_fee: U256, + already_withdrawn: Self::LiquidityInfo, + ) -> Self::LiquidityInfo { + ::Currency, OU> as OnChargeEVMTransactionT< + T, + >>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn) + } + + fn pay_priority_fee(tip: Self::LiquidityInfo) { + if let Some(tip) = tip { + OU::on_unbalanced(tip); + } + } + } + } +} diff --git a/tracing/3100/runtime/common/src/impl_self_contained_call.rs b/tracing/3100/runtime/common/src/impl_self_contained_call.rs new file mode 100644 index 00000000..0dbce052 --- /dev/null +++ b/tracing/3100/runtime/common/src/impl_self_contained_call.rs @@ -0,0 +1,78 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_self_contained_call { + {} => { + impl fp_self_contained::SelfContainedCall for RuntimeCall { + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + fn check_self_contained( + &self + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + signed_info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(signed_info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.pre_dispatch_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => Some( + call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info) + )) + ), + _ => None, + } + } + } + } +} diff --git a/tracing/3100/runtime/common/src/impl_xcm_evm_runner.rs b/tracing/3100/runtime/common/src/impl_xcm_evm_runner.rs new file mode 100644 index 00000000..07102147 --- /dev/null +++ b/tracing/3100/runtime/common/src/impl_xcm_evm_runner.rs @@ -0,0 +1,242 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_evm_runner_precompile_or_eth_xcm { + {} => { + use fp_evm::{CallInfo, CallOrCreateInfo, Context, Transfer}; + use frame_support::dispatch::CallableCallFor; + use pallet_evm::{Runner, RunnerError}; + use precompile_utils::{prelude::*, evm::handle::with_precompile_handle}; + use sp_core::U256; + use sp_runtime::DispatchError; + use sp_std::vec::Vec; + use xcm_primitives::{EthereumXcmTransaction, EthereumXcmTransactionV2}; + + pub struct EvmRunnerPrecompileOrEthXcm( + core::marker::PhantomData<(CallDispatcher, Runtime)>, + ); + + impl Runner + for EvmRunnerPrecompileOrEthXcm + where + CallDispatcher: xcm_executor::traits::CallDispatcher, + Runtime: pallet_evm::Config + pallet_ethereum_xcm::Config, + Runtime::RuntimeOrigin: From, + { + type Error = DispatchError; + + fn call( + source: H160, + target: H160, + input: Vec, + value: U256, + gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + // The `with_precompile_handle` function will execute the closure (and return the + // result in a Some) if and only if there is an available EVM context. Otherwise, + // it will return None. + if let Some((exit_reason, value)) = with_precompile_handle(|precompile_handle| { + let transfer = if value.is_zero() { + None + } else { + Some(Transfer { + source, + target, + value, + }) + }; + + precompile_handle.call( + target, + transfer, + input.clone(), + Some(gas_limit), + false, + &Context { + address: target, + caller: source, + apparent_value: value, + }, + ) + }) { + Ok(CallInfo { + exit_reason, + value, + used_gas: fp_evm::UsedGas { + standard: U256::default(), + effective: U256::default(), + }, + logs: Default::default(), + weight_info: None, + }) + } else { + let xcm_transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { + gas_limit: gas_limit.into(), + action: pallet_ethereum_xcm::TransactionAction::Call(target), + value, + input: input.try_into().map_err(|_| RunnerError { + error: DispatchError::Exhausted, + weight: Default::default(), + })?, + access_list: Some(access_list), + }); + + let mut execution_info: Option = None; + pallet_ethereum::catch_exec_info(&mut execution_info, || { + CallDispatcher::dispatch( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { xcm_transaction }), + RawOrigin::Signed(source.into()).into(), + ) + .map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError { + error, + weight: Default::default(), + }) + })?; + + if let Some(CallOrCreateInfo::Call(call_info))= execution_info { + Ok(call_info) + } else { + // `execution_info` must have been filled in + Err(RunnerError { + error: DispatchError::Unavailable, + weight: Default::default(), + }) + } + } + } + + fn create( + _source: H160, + _init: Vec, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + unimplemented!() + } + + fn create2( + _source: H160, + _init: Vec, + _salt: H256, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + unimplemented!() + } + + fn create_force_address( + source: H160, + init: Vec, + value: U256, + gas_limit: u64, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Vec<(H160, Vec)>, + is_transactional: bool, + validate: bool, + weight_limit: Option, + transaction_len: Option, + config: &fp_evm::Config, + force_address: H160, + ) -> Result> { + let xcm_transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { + gas_limit: gas_limit.into(), + action: pallet_ethereum_xcm::TransactionAction::Create, + value, + input: init.try_into().map_err(|_| RunnerError { + error: DispatchError::Exhausted, + weight: Default::default(), + })?, + access_list: Some(access_list), + }); + + let mut execution_info: Option = None; + pallet_ethereum::catch_exec_info(&mut execution_info, || { + CallDispatcher::dispatch( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::force_transact_as { + transact_as: source, + xcm_transaction, + force_create_address: Some(force_address), + }), + RawOrigin::Root.into(), + ) + .map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError { + error, + weight: Default::default(), + }) + })?; + + if let Some(CallOrCreateInfo::Create(create_info))= execution_info { + Ok(create_info) + } else { + // `execution_info` must have been filled in + Err(RunnerError { + error: DispatchError::Unavailable, + weight: Default::default(), + }) + } + } + + fn validate( + _source: H160, + _target: Option, + _input: Vec, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _weight_limit: Option, + _transaction_len: Option, + _evm_config: &fp_evm::Config, + ) -> Result<(), RunnerError> { + unimplemented!() + } + } + + } +} diff --git a/tracing/3100/runtime/common/src/lib.rs b/tracing/3100/runtime/common/src/lib.rs new file mode 100644 index 00000000..747a8a32 --- /dev/null +++ b/tracing/3100/runtime/common/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +mod apis; +mod impl_moonbeam_xcm_call; +mod impl_moonbeam_xcm_call_tracing; +mod impl_on_charge_evm_transaction; +mod impl_self_contained_call; +mod impl_xcm_evm_runner; +pub mod migrations; +pub mod timestamp; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; diff --git a/tracing/3100/runtime/common/src/migrations.rs b/tracing/3100/runtime/common/src/migrations.rs new file mode 100644 index 00000000..ea062092 --- /dev/null +++ b/tracing/3100/runtime/common/src/migrations.rs @@ -0,0 +1,199 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Migrations +//! +//! This module acts as a registry where each migration is defined. Each migration should implement +//! the "Migration" trait declared in the pallet-migrations crate. + +use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{marker::PhantomData, prelude::*, vec}; + +pub struct MigrateToLatestXcmVersion(PhantomData); +impl Migration for MigrateToLatestXcmVersion +where + pallet_xcm::migration::MigrateToLatestXcmVersion: OnRuntimeUpgrade, +{ + fn friendly_name(&self) -> &str { + "MM_MigrateToLatestXcmVersion" + } + + fn migrate(&self, _available_weight: Weight) -> Weight { + pallet_xcm::migration::MigrateToLatestXcmVersion::::on_runtime_upgrade() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { + pallet_xcm::migration::MigrateToLatestXcmVersion::::pre_upgrade() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(&self, state: Vec) -> Result<(), sp_runtime::DispatchError> { + pallet_xcm::migration::MigrateToLatestXcmVersion::::post_upgrade(state) + } +} + +pub struct CommonMigrations(PhantomData); + +impl GetMigrations for CommonMigrations +where + Runtime: pallet_xcm::Config, + Runtime::AccountId: Default, + BlockNumberFor: Into, +{ + fn get_migrations() -> Vec> { + // let migration_author_mapping_twox_to_blake = AuthorMappingTwoXToBlake:: { + // 0: Default::default(), + // }; + + // let migration_parachain_staking_purge_stale_storage = + // ParachainStakingPurgeStaleStorage::(Default::default()); + // let migration_parachain_staking_manual_exits = + // ParachainStakingManualExits::(Default::default()); + // let migration_parachain_staking_increase_max_delegations_per_candidate = + // ParachainStakingIncreaseMaxDelegationsPerCandidate::(Default::default()); + // let migration_parachain_staking_split_candidate_state = + // ParachainStakingSplitCandidateState::(Default::default()); + // let migration_parachain_staking_patch_incorrect_delegation_sums = + // ParachainStakingPatchIncorrectDelegationSums::(Default::default()); + + // let migration_scheduler_v3 = SchedulerMigrationV3::(Default::default()); + + // let migration_base_fee = MigrateBaseFeePerGas::(Default::default()); + + // TODO: this is a lot of allocation to do upon every get() call. this *should* be avoided + // except when pallet_migrations undergoes a runtime upgrade -- but TODO: review + + // let migration_author_slot_filter_eligible_ratio_to_eligibility_count = + // AuthorSlotFilterEligibleRatioToEligiblityCount::(Default::default()); + // let migration_author_mapping_add_keys_to_registration_info = + // AuthorMappingAddKeysToRegistrationInfo::(Default::default()); + // let staking_delegator_state_requests = + // ParachainStakingSplitDelegatorStateIntoDelegationScheduledRequests::( + // Default::default(), + // ); + // let migration_author_mapping_add_account_id_to_nimbus_lookup = + // AuthorMappingAddAccountIdToNimbusLookup::(Default::default()); + + // let xcm_transactor_max_weight = + // XcmTransactorMaxTransactWeight::(Default::default()); + + // let asset_manager_units_with_asset_type = + // AssetManagerUnitsWithAssetType::(Default::default()); + + // let asset_manager_populate_asset_type_id_storage = + // AssetManagerPopulateAssetTypeIdStorage::(Default::default()); + + // let asset_manager_change_statemine_prefixes = AssetManagerChangeStateminePrefixes::< + // Runtime, + // StatemineParaIdInfo, + // StatemineAssetsInstanceInfo, + // >(Default::default()); + + // let xcm_supported_assets = XcmPaymentSupportedAssets::(Default::default()); + + // let migration_elasticity = MigrateBaseFeeElasticity::(Default::default()); + //let staking_at_stake_auto_compound = + // ParachainStakingMigrateAtStakeAutoCompound::(Default::default()); + + //let scheduler_to_v4 = SchedulerMigrationV4::(Default::default()); + //let democracy_migration_hash_to_bounded_call = + // DemocracryMigrationHashToBoundedCall::(Default::default()); + //let preimage_migration_hash_to_bounded_call = + // PreimageMigrationHashToBoundedCall::(Default::default()); + //let asset_manager_to_xcm_v3 = + // PalletAssetManagerMigrateXcmV2ToV3::(Default::default()); + //let xcm_transactor_to_xcm_v3 = + // PalletXcmTransactorMigrateXcmV2ToV3::(Default::default()); + //let remove_min_bond_for_old_orbiter_collators = + // RemoveMinBondForOrbiterCollators::(Default::default()); + // let missing_balances_migrations = MissingBalancesMigrations::(Default::default()); + // let fix_pallet_versions = + // FixIncorrectPalletVersions::(Default::default()); + // let pallet_referenda_migrate_v0_to_v1 = + // PalletReferendaMigrateV0ToV1::(Default::default()); + //let pallet_collective_drop_gov_v1_collectives = + // PalletCollectiveDropGovV1Collectives::(Default::default()); + //let pallet_staking_round = PalletStakingRoundMigration::(Default::default()); + + vec![ + // completed in runtime 800 + // Box::new(migration_author_mapping_twox_to_blake), + // completed in runtime 900 + // completed in runtime 1000 + // Box::new(migration_parachain_staking_purge_stale_storage), + // completed in runtime 1000 + // Box::new(migration_parachain_staking_manual_exits), + // completed in runtime 1101 + // Box::new(migration_parachain_staking_increase_max_delegations_per_candidate), + // completed in runtime 1201 + // Box::new(migration_parachain_staking_split_candidate_state), + // completed in runtime 1201 + // Box::new(xcm_transactor_max_weight), + // completed in runtime 1201 + // Box::new(asset_manager_units_with_asset_type), + // completed in runtime 1201 + // Box::new(asset_manager_change_statemine_prefixes), + // completed in runtime 1201 + // Box::new(asset_manager_populate_asset_type_id_storage), + // completed in runtime 1300 + // Box::new(migration_scheduler_v3), + // completed in runtime 1300 + // Box::new(migration_parachain_staking_patch_incorrect_delegation_sums), + // completed in runtime 1300 + // Box::new(migration_base_fee), + // completed in runtime 1300 + // Box::new(xcm_supported_assets), + // completed in runtime 1500 + // Box::new(migration_author_slot_filter_eligible_ratio_to_eligibility_count), + // Box::new(migration_author_mapping_add_keys_to_registration_info), + // Box::new(staking_delegator_state_requests), + // completed in runtime 1600 + // Box::new(migration_author_mapping_add_account_id_to_nimbus_lookup), + // completed in runtime 1600 + // Box::new(xcm_transactor_transact_signed), + // completed in runtime 1700 + //Box::new(migration_elasticity), + // completed in runtime 1900 + //Box::new(staking_at_stake_auto_compound), + // completed in runtime 2000 + //Box::new(scheduler_to_v4), + //Box::new(democracy_migration_hash_to_bounded_call), + //Box::new(preimage_migration_hash_to_bounded_call), + // completed in runtime 2100 + //Box::new(asset_manager_to_xcm_v3), + //Box::new(xcm_transactor_to_xcm_v3), + // completed in runtime 2600 + //Box::new(remove_min_bond_for_old_orbiter_collators), + // completed in runtime 2700 + // Box::new(missing_balances_migrations), + // Box::new(fix_pallet_versions), + // Box::new(pallet_referenda_migrate_v0_to_v1), + // completed in runtime 2800 + //Box::new(pallet_collective_drop_gov_v1_collectives), + // completed in runtime 2801 + // Box::new(pallet_staking_round), + // Box::new(pallet_collective_drop_gov_v1_collectives), + // completed in runtime 2900 + // Box::new(remove_pallet_democracy), + // Box::new(remove_collectives_addresses), + // permanent migrations + Box::new(MigrateToLatestXcmVersion::(Default::default())), + ] + } +} diff --git a/tracing/3100/runtime/common/src/timestamp.rs b/tracing/3100/runtime/common/src/timestamp.rs new file mode 100644 index 00000000..82a67ef3 --- /dev/null +++ b/tracing/3100/runtime/common/src/timestamp.rs @@ -0,0 +1,92 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! A way to get a relyable timestamp + +use cumulus_pallet_parachain_system::{ + consensus_hook::UnincludedSegmentCapacity, + relay_state_snapshot::{self, ReadEntryErr}, + ConsensusHook, RelayChainStateProof, +}; +use frame_support::pallet_prelude::*; +use frame_support::storage::types::{StorageValue, ValueQuery}; +use frame_support::traits::{StorageInstance, Time}; +pub use moonbeam_core_primitives::well_known_relay_keys; + +/// Get the relay timestamp. +/// Noe that the relay timestamp is populated at the parachain system inherent. +/// If you fetch the timestamp before, you will get the timestamp of the parent block. +pub struct RelayTimestamp; +impl Time for RelayTimestamp { + type Moment = u64; + + fn now() -> Self::Moment { + RelayTimestampNow::get() + } +} + +/// A wrapper around the consensus hook to get the relay timestamp from the relay storage proof +pub struct ConsensusHookWrapperForRelayTimestamp( + core::marker::PhantomData<(Runtime, Inner)>, +); +impl ConsensusHook for ConsensusHookWrapperForRelayTimestamp +where + Runtime: frame_system::Config, + Inner: ConsensusHook, +{ + fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) { + let relay_timestamp: u64 = + match state_proof.read_entry(well_known_relay_keys::TIMESTAMP_NOW, None) { + Ok(relay_timestamp) => relay_timestamp, + // Log the read entry error + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Proof)) => { + log::error!("Invalid relay storage proof: fail to read key TIMESTAMP_NOW"); + panic!("Invalid realy storage proof: fail to read key TIMESTAMP_NOW"); + } + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Decode)) => { + log::error!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW"); + panic!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW"); + } + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Absent)) => { + log::error!("Corrupted relay storage: value TIMESTAMP_NOW is absent!"); + panic!("Corrupted relay storage: value TIMESTAMP_NOW is absent!"); + } + // Can't return another kind of error, the blokc is invalid anyway, so we should panic + _ => unreachable!(), + }; + + let wrapper_weight = ::DbWeight::get().writes(1); + + RelayTimestampNow::put(relay_timestamp); + + let (weight, capacity) = Inner::on_state_proof(state_proof); + + (weight.saturating_add(wrapper_weight), capacity) + } +} + +// Prefix for storage value RelayTimestampNow +struct RelayTimestampNowPrefix; +impl StorageInstance for RelayTimestampNowPrefix { + const STORAGE_PREFIX: &'static str = "RelayTimestampNow"; + + fn pallet_prefix() -> &'static str { + "runtime" + } +} + +// Storage type used to store the last current relay timestamp +type RelayTimestampNow = StorageValue; diff --git a/tracing/3100/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs b/tracing/3100/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 00000000..1a2e88a3 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs @@ -0,0 +1,154 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=cumulus_pallet_xcmp_queue +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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 `cumulus_pallet_xcmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_u32() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1627` + // Minimum execution time: 4_307_000 picoseconds. + Weight::from_parts(4_445_000, 1627) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(134193), added: 136668, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `148` + // Estimated: `3517` + // Minimum execution time: 11_285_000 picoseconds. + Weight::from_parts(11_795_000, 3517) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1627` + // Minimum execution time: 2_760_000 picoseconds. + Weight::from_parts(2_884_000, 1627) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `177` + // Estimated: `1662` + // Minimum execution time: 3_600_000 picoseconds. + Weight::from_parts(3_734_000, 1662) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_631_000 picoseconds. + Weight::from_parts(8_118_000, 0) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(134193), added: 136668, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `134385` + // Estimated: `137850` + // Minimum execution time: 190_123_000 picoseconds. + Weight::from_parts(194_387_000, 137850) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(134193), added: 136668, mode: `MaxEncodedLen`) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65782` + // Estimated: `69247` + // Minimum execution time: 102_726_000 picoseconds. + Weight::from_parts(104_463_000, 69247) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/mod.rs b/tracing/3100/runtime/common/src/weights/mod.rs new file mode 100644 index 00000000..02b42372 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/mod.rs @@ -0,0 +1,49 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam common weights. + +pub mod cumulus_pallet_xcmp_queue; +pub mod pallet_asset_manager; +pub mod pallet_assets; +pub mod pallet_author_inherent; +pub mod pallet_author_mapping; +pub mod pallet_author_slot_filter; +pub mod pallet_balances; +pub mod pallet_collective; +pub mod pallet_conviction_voting; +pub mod pallet_crowdloan_rewards; +pub mod pallet_evm; +pub mod pallet_identity; +pub mod pallet_moonbeam_foreign_assets; +pub mod pallet_moonbeam_lazy_migrations; +pub mod pallet_moonbeam_orbiters; +pub mod pallet_multisig; +pub mod pallet_parachain_staking; +pub mod pallet_precompile_benchmarks; +pub mod pallet_preimage; +pub mod pallet_proxy; +pub mod pallet_randomness; +pub mod pallet_referenda; +pub mod pallet_relay_storage_roots; +pub mod pallet_scheduler; +pub mod pallet_sudo; +pub mod pallet_timestamp; +pub mod pallet_treasury; +pub mod pallet_utility; +pub mod pallet_whitelist; +pub mod pallet_xcm; +pub mod pallet_xcm_transactor; diff --git a/tracing/3100/runtime/common/src/weights/pallet_asset_manager.rs b/tracing/3100/runtime/common/src/weights/pallet_asset_manager.rs new file mode 100644 index 00000000..9d0ed109 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_asset_manager.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_asset_manager` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_asset_manager +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_asset_manager`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_manager::WeightInfo for WeightInfo { + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3639` + // Minimum execution time: 28_927_000 picoseconds. + Weight::from_parts(29_493_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::SupportedFeePaymentAssets` (r:1 w:1) + /// Proof: `AssetManager::SupportedFeePaymentAssets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeUnitsPerSecond` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeUnitsPerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn set_asset_units_per_second(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `611 + x * (9 ±0)` + // Estimated: `4000 + x * (10 ±0)` + // Minimum execution time: 19_578_000 picoseconds. + Weight::from_parts(18_705_391, 4000) + // Standard Error: 3_442 + .saturating_add(Weight::from_parts(792_309, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(x.into())) + } + /// Storage: `AssetManager::SupportedFeePaymentAssets` (r:1 w:1) + /// Proof: `AssetManager::SupportedFeePaymentAssets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeUnitsPerSecond` (r:1 w:2) + /// Proof: `AssetManager::AssetTypeUnitsPerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:2) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn change_existing_asset_type(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `926 + x * (13 ±0)` + // Estimated: `4309 + x * (15 ±0)` + // Minimum execution time: 29_180_000 picoseconds. + Weight::from_parts(29_891_006, 4309) + // Standard Error: 4_391 + .saturating_add(Weight::from_parts(874_012, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_parts(0, 15).saturating_mul(x.into())) + } + /// Storage: `AssetManager::SupportedFeePaymentAssets` (r:1 w:1) + /// Proof: `AssetManager::SupportedFeePaymentAssets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeUnitsPerSecond` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeUnitsPerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn remove_supported_asset(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `196 + x * (5 ±0)` + // Estimated: `1678 + x * (5 ±0)` + // Minimum execution time: 15_115_000 picoseconds. + Weight::from_parts(13_493_610, 1678) + // Standard Error: 2_952 + .saturating_add(Weight::from_parts(694_325, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(x.into())) + } + /// Storage: `AssetManager::SupportedFeePaymentAssets` (r:1 w:1) + /// Proof: `AssetManager::SupportedFeePaymentAssets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeUnitsPerSecond` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeUnitsPerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn remove_existing_asset_type(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `482 + x * (10 ±0)` + // Estimated: `3955 + x * (10 ±0)` + // Minimum execution time: 21_219_000 picoseconds. + Weight::from_parts(20_476_212, 3955) + // Standard Error: 3_389 + .saturating_add(Weight::from_parts(716_188, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(x.into())) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_assets.rs b/tracing/3100/runtime/common/src/weights/pallet_assets.rs new file mode 100644 index 00000000..c809d386 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_assets.rs @@ -0,0 +1,485 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_assets +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_assets::WeightInfo for WeightInfo { + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3639` + // Minimum execution time: 8_540_000 picoseconds. + Weight::from_parts(8_819_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn start_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 10_093_000 picoseconds. + Weight::from_parts(10_366_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:657 w:656) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:656 w:656) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 656]`. + fn destroy_accounts(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1514 + c * (183 ±0)` + // Estimated: `3639 + c * (2597 ±0)` + // Minimum execution time: 14_670_000 picoseconds. + Weight::from_parts(14_889_000, 3639) + // Standard Error: 7_930 + .saturating_add(Weight::from_parts(15_505_771, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(c.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:657 w:656) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 656]`. + fn destroy_approvals(a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `313 + a * (74 ±0)` + // Estimated: `3639 + a * (2611 ±0)` + // Minimum execution time: 15_548_000 picoseconds. + Weight::from_parts(15_849_000, 3639) + // Standard Error: 6_606 + .saturating_add(Weight::from_parts(8_201_913, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 2611).saturating_mul(a.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn finish_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 10_773_000 picoseconds. + Weight::from_parts(11_122_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 19_924_000 picoseconds. + Weight::from_parts(20_391_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 27_019_000 picoseconds. + Weight::from_parts(27_599_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 39_049_000 picoseconds. + Weight::from_parts(40_100_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 35_211_000 picoseconds. + Weight::from_parts(35_851_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 39_056_000 picoseconds. + Weight::from_parts(39_932_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 14_006_000 picoseconds. + Weight::from_parts(14_200_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 13_885_000 picoseconds. + Weight::from_parts(14_219_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn freeze_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 9_803_000 picoseconds. + Weight::from_parts(10_142_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn thaw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 9_778_000 picoseconds. + Weight::from_parts(10_129_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 11_361_000 picoseconds. + Weight::from_parts(11_617_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 9_644_000 picoseconds. + Weight::from_parts(9_912_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 24_783_000 picoseconds. + Weight::from_parts(25_608_406, 3639) + // Standard Error: 512 + .saturating_add(Weight::from_parts(2_492, 0).saturating_mul(n.into())) + // Standard Error: 512 + .saturating_add(Weight::from_parts(3_292, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3639` + // Minimum execution time: 25_888_000 picoseconds. + Weight::from_parts(26_609_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3639` + // Minimum execution time: 10_297_000 picoseconds. + Weight::from_parts(10_766_456, 3639) + // Standard Error: 250 + .saturating_add(Weight::from_parts(2_473, 0).saturating_mul(n.into())) + // Standard Error: 250 + .saturating_add(Weight::from_parts(1_563, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn force_clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3639` + // Minimum execution time: 25_777_000 picoseconds. + Weight::from_parts(26_277_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn force_asset_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 9_301_000 picoseconds. + Weight::from_parts(9_593_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 15_835_000 picoseconds. + Weight::from_parts(16_276_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `513` + // Estimated: `6184` + // Minimum execution time: 47_549_000 picoseconds. + Weight::from_parts(48_475_000, 6184) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `399` + // Estimated: `3639` + // Minimum execution time: 17_503_000 picoseconds. + Weight::from_parts(18_222_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn force_cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `399` + // Estimated: `3639` + // Minimum execution time: 17_938_000 picoseconds. + Weight::from_parts(18_370_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 10_607_000 picoseconds. + Weight::from_parts(10_812_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3639` + // Minimum execution time: 30_374_000 picoseconds. + Weight::from_parts(31_039_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 28_233_000 picoseconds. + Weight::from_parts(28_956_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `561` + // Estimated: `3639` + // Minimum execution time: 29_630_000 picoseconds. + Weight::from_parts(30_038_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `3639` + // Minimum execution time: 26_942_000 picoseconds. + Weight::from_parts(27_906_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 13_661_000 picoseconds. + Weight::from_parts(14_030_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_author_inherent.rs b/tracing/3100/runtime/common/src/weights/pallet_author_inherent.rs new file mode 100644 index 00000000..566f0cdf --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_author_inherent.rs @@ -0,0 +1,70 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_inherent` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_inherent +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_author_inherent`. +pub struct WeightInfo(PhantomData); +impl pallet_author_inherent::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorInherent::Author` (r:1 w:0) + /// Proof: `AuthorInherent::Author` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:1 w:0) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorFilter::EligibleCount` (r:1 w:0) + /// Proof: `AuthorFilter::EligibleCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::PreviousLocalVrfOutput` (r:1 w:0) + /// Proof: `Randomness::PreviousLocalVrfOutput` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorInherent::InherentIncluded` (r:0 w:1) + /// Proof: `AuthorInherent::InherentIncluded` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + fn kick_off_authorship_validation() -> Weight { + // Proof Size summary in bytes: + // Measured: `372` + // Estimated: `1857` + // Minimum execution time: 17_699_000 picoseconds. + Weight::from_parts(18_069_000, 1857) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_author_mapping.rs b/tracing/3100/runtime/common/src/weights/pallet_author_mapping.rs new file mode 100644 index 00000000..5962bfb2 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_author_mapping.rs @@ -0,0 +1,122 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_mapping` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_mapping +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_author_mapping`. +pub struct WeightInfo(PhantomData); +impl pallet_author_mapping::WeightInfo for WeightInfo { + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `376` + // Estimated: `3841` + // Minimum execution time: 27_141_000 picoseconds. + Weight::from_parts(27_986_000, 3841) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::MappingWithDeposit` (r:2 w:2) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `6265` + // Minimum execution time: 17_559_000 picoseconds. + Weight::from_parts(18_098_000, 6265) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn clear_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `3918` + // Minimum execution time: 28_254_000 picoseconds. + Weight::from_parts(28_962_000, 3918) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::NimbusLookup` (r:1 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn remove_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `4012` + // Minimum execution time: 34_198_000 picoseconds. + Weight::from_parts(35_209_000, 4012) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::NimbusLookup` (r:1 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn set_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `432` + // Estimated: `3897` + // Minimum execution time: 30_189_000 picoseconds. + Weight::from_parts(30_839_000, 3897) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_author_slot_filter.rs b/tracing/3100/runtime/common/src/weights/pallet_author_slot_filter.rs new file mode 100644 index 00000000..1a29269f --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_author_slot_filter.rs @@ -0,0 +1,59 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_slot_filter` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_slot_filter +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_author_slot_filter`. +pub struct WeightInfo(PhantomData); +impl pallet_author_slot_filter::WeightInfo for WeightInfo { + /// Storage: `AuthorFilter::EligibleCount` (r:0 w:1) + /// Proof: `AuthorFilter::EligibleCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_eligible() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_198_000 picoseconds. + Weight::from_parts(4_335_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_balances.rs b/tracing/3100/runtime/common/src/weights/pallet_balances.rs new file mode 100644 index 00000000..bc83ef82 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_balances.rs @@ -0,0 +1,151 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_balances` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_balances +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_balances`. +pub struct WeightInfo(PhantomData); +impl pallet_balances::WeightInfo for WeightInfo { + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 43_826_000 picoseconds. + Weight::from_parts(45_231_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 37_723_000 picoseconds. + Weight::from_parts(39_155_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_set_balance_creating() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 14_323_000 picoseconds. + Weight::from_parts(14_926_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_set_balance_killing() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 19_305_000 picoseconds. + Weight::from_parts(19_884_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `267` + // Estimated: `6172` + // Minimum execution time: 46_320_000 picoseconds. + Weight::from_parts(47_662_000, 6172) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 46_606_000 picoseconds. + Weight::from_parts(47_951_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 17_080_000 picoseconds. + Weight::from_parts(17_978_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1277 + u * (123 ±0)` + // Estimated: `990 + u * (2591 ±0)` + // Minimum execution time: 15_800_000 picoseconds. + Weight::from_parts(16_120_000, 990) + // Standard Error: 8_673 + .saturating_add(Weight::from_parts(13_383_939, 0).saturating_mul(u.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(u.into())) + } + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + fn force_adjust_total_issuance() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1501` + // Minimum execution time: 5_845_000 picoseconds. + Weight::from_parts(6_125_000, 1501) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_collective.rs b/tracing/3100/runtime/common/src/weights/pallet_collective.rs new file mode 100644 index 00000000..5c70e97f --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_collective.rs @@ -0,0 +1,308 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . +//! Autogenerated weights for `pallet_collective` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_collective +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_collective`. +pub struct WeightInfo(PhantomData); +impl pallet_collective::WeightInfo for WeightInfo { + /// Storage: CouncilCollective Members (r:1 w:1) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:0) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:100 w:100) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:0 w:1) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `m` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `p` is `[0, 100]`. + fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + m * (2021 ±0) + p * (2026 ±0)` + // Estimated: `12238 + m * (1231 ±14) + p * (3660 ±14)` + // Minimum execution time: 13_785_000 picoseconds. + Weight::from_parts(14_085_000, 0) + .saturating_add(Weight::from_parts(0, 12238)) + // Standard Error: 34_315 + .saturating_add(Weight::from_parts(2_414_144, 0).saturating_mul(m.into())) + // Standard Error: 34_315 + .saturating_add(Weight::from_parts(5_345_562, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 1231).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3660).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + m * (20 ±0)` + // Estimated: `1634 + m * (20 ±0)` + // Minimum execution time: 12_726_000 picoseconds. + Weight::from_parts(12_294_605, 0) + .saturating_add(Weight::from_parts(0, 1634)) + // Standard Error: 18 + .saturating_add(Weight::from_parts(910, 0).saturating_mul(b.into())) + // Standard Error: 192 + .saturating_add(Weight::from_parts(13_235, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:0) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn propose_execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + m * (20 ±0)` + // Estimated: `3614 + m * (20 ±0)` + // Minimum execution time: 14_722_000 picoseconds. + Weight::from_parts(14_487_427, 0) + .saturating_add(Weight::from_parts(0, 3614)) + // Standard Error: 20 + .saturating_add(Weight::from_parts(944, 0).saturating_mul(b.into())) + // Standard Error: 215 + .saturating_add(Weight::from_parts(25_619, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalCount (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:0 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `395 + m * (20 ±0) + p * (36 ±0)` + // Estimated: `3789 + m * (21 ±0) + p * (36 ±0)` + // Minimum execution time: 17_107_000 picoseconds. + Weight::from_parts(15_172_014, 0) + .saturating_add(Weight::from_parts(0, 3789)) + // Standard Error: 104 + .saturating_add(Weight::from_parts(3_191, 0).saturating_mul(b.into())) + // Standard Error: 1_090 + .saturating_add(Weight::from_parts(31_145, 0).saturating_mul(m.into())) + // Standard Error: 1_077 + .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 21).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `870 + m * (40 ±0)` + // Estimated: `4334 + m * (40 ±0)` + // Minimum execution time: 21_423_000 picoseconds. + Weight::from_parts(22_311_906, 0) + .saturating_add(Weight::from_parts(0, 4334)) + // Standard Error: 415 + .saturating_add(Weight::from_parts(32_990, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + m * (40 ±0) + p * (36 ±0)` + // Estimated: `3892 + m * (41 ±0) + p * (36 ±0)` + // Minimum execution time: 20_010_000 picoseconds. + Weight::from_parts(20_008_777, 0) + .saturating_add(Weight::from_parts(0, 3892)) + // Standard Error: 1_391 + .saturating_add(Weight::from_parts(39_960, 0).saturating_mul(m.into())) + // Standard Error: 1_356 + .saturating_add(Weight::from_parts(126_447, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 41).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `791 + b * (1 ±0) + m * (40 ±0) + p * (40 ±0)` + // Estimated: `4108 + b * (1 ±0) + m * (42 ±0) + p * (40 ±0)` + // Minimum execution time: 30_647_000 picoseconds. + Weight::from_parts(30_084_699, 0) + .saturating_add(Weight::from_parts(0, 4108)) + // Standard Error: 123 + .saturating_add(Weight::from_parts(2_876, 0).saturating_mul(b.into())) + // Standard Error: 1_307 + .saturating_add(Weight::from_parts(31_661, 0).saturating_mul(m.into())) + // Standard Error: 1_274 + .saturating_add(Weight::from_parts(154_567, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:1 w:0) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `516 + m * (30 ±0) + p * (36 ±0)` + // Estimated: `3958 + m * (31 ±0) + p * (36 ±0)` + // Minimum execution time: 20_735_000 picoseconds. + Weight::from_parts(22_649_363, 0) + .saturating_add(Weight::from_parts(0, 3958)) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(32_331, 0).saturating_mul(m.into())) + // Standard Error: 1_055 + .saturating_add(Weight::from_parts(122_034, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 31).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:1 w:0) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `811 + b * (1 ±0) + m * (40 ±0) + p * (40 ±0)` + // Estimated: `4128 + b * (1 ±0) + m * (42 ±0) + p * (40 ±0)` + // Minimum execution time: 32_927_000 picoseconds. + Weight::from_parts(32_086_367, 0) + .saturating_add(Weight::from_parts(0, 4128)) + // Standard Error: 122 + .saturating_add(Weight::from_parts(2_962, 0).saturating_mul(b.into())) + // Standard Error: 1_299 + .saturating_add(Weight::from_parts(32_167, 0).saturating_mul(m.into())) + // Standard Error: 1_266 + .saturating_add(Weight::from_parts(154_131, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:0 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `p` is `[1, 100]`. + fn disapprove_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `264 + p * (32 ±0)` + // Estimated: `1749 + p * (32 ±0)` + // Minimum execution time: 10_334_000 picoseconds. + Weight::from_parts(11_413_201, 0) + .saturating_add(Weight::from_parts(0, 1749)) + // Standard Error: 1_033 + .saturating_add(Weight::from_parts(95_458, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_conviction_voting.rs b/tracing/3100/runtime/common/src/weights/pallet_conviction_voting.rs new file mode 100644 index 00000000..dd8bb695 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_conviction_voting.rs @@ -0,0 +1,192 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_conviction_voting` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_conviction_voting +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_conviction_voting`. +pub struct WeightInfo(PhantomData); +impl pallet_conviction_voting::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn vote_new() -> Weight { + // Proof Size summary in bytes: + // Measured: `1962` + // Estimated: `42428` + // Minimum execution time: 63_183_000 picoseconds. + Weight::from_parts(64_601_000, 42428) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn vote_existing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2263` + // Estimated: `83866` + // Minimum execution time: 84_800_000 picoseconds. + Weight::from_parts(85_964_000, 83866) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn remove_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `1841` + // Estimated: `83866` + // Minimum execution time: 57_451_000 picoseconds. + Weight::from_parts(58_541_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn remove_other_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `1385` + // Estimated: `4617` + // Minimum execution time: 19_644_000 picoseconds. + Weight::from_parts(20_527_000, 4617) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:20 w:20) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:20) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 20]`. + fn delegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1621 + r * (248 ±0)` + // Estimated: `83866 + r * (3387 ±0)` + // Minimum execution time: 42_633_000 picoseconds. + Weight::from_parts(38_091_643, 83866) + // Standard Error: 77_374 + .saturating_add(Weight::from_parts(26_302_549, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3387).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:20 w:20) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:20) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 20]`. + fn undelegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1340 + r * (248 ±0)` + // Estimated: `83866 + r * (3387 ±0)` + // Minimum execution time: 19_458_000 picoseconds. + Weight::from_parts(11_738_092, 83866) + // Standard Error: 78_434 + .saturating_add(Weight::from_parts(25_800_751, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3387).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `1228` + // Estimated: `4752` + // Minimum execution time: 46_940_000 picoseconds. + Weight::from_parts(48_064_000, 4752) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_crowdloan_rewards.rs b/tracing/3100/runtime/common/src/weights/pallet_crowdloan_rewards.rs new file mode 100644 index 00000000..8aff78a6 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_crowdloan_rewards.rs @@ -0,0 +1,163 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_crowdloan_rewards` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_crowdloan_rewards +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_crowdloan_rewards`. +pub struct WeightInfo(PhantomData); +impl pallet_crowdloan_rewards::WeightInfo for WeightInfo { + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:0) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitializedRewardAmount` (r:1 w:1) + /// Proof: `CrowdloanRewards::InitializedRewardAmount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::TotalContributors` (r:1 w:1) + /// Proof: `CrowdloanRewards::TotalContributors` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:501 w:501) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `CrowdloanRewards::ClaimedRelayChainIds` (r:500 w:500) + /// Proof: `CrowdloanRewards::ClaimedRelayChainIds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::UnassociatedContributions` (r:500 w:0) + /// Proof: `CrowdloanRewards::UnassociatedContributions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:500 w:500) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 500]`. + fn initialize_reward_vec(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `76347 + x * (550 ±0)` + // Estimated: `66242 + x * (3052 ±5)` + // Minimum execution time: 101_419_000 picoseconds. + Weight::from_parts(78_107_785, 66242) + // Standard Error: 16_867 + .saturating_add(Weight::from_parts(53_012_102, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3052).saturating_mul(x.into())) + } + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:1) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitializedRewardAmount` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitializedRewardAmount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `CrowdloanRewards::TotalContributors` (r:1 w:0) + /// Proof: `CrowdloanRewards::TotalContributors` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::EndRelayBlock` (r:0 w:1) + /// Proof: `CrowdloanRewards::EndRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn complete_initialization() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `3581` + // Minimum execution time: 14_662_000 picoseconds. + Weight::from_parts(14_928_000, 3581) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:0) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:1 w:1) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::EndRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::EndRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn claim() -> Weight { + // Proof Size summary in bytes: + // Measured: `1100` + // Estimated: `6172` + // Minimum execution time: 60_474_000 picoseconds. + Weight::from_parts(61_425_000, 6172) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `CrowdloanRewards::AccountsPayable` (r:2 w:2) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_reward_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `397` + // Estimated: `6337` + // Minimum execution time: 17_193_000 picoseconds. + Weight::from_parts(17_599_000, 6337) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `CrowdloanRewards::UnassociatedContributions` (r:1 w:1) + /// Proof: `CrowdloanRewards::UnassociatedContributions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::ClaimedRelayChainIds` (r:1 w:1) + /// Proof: `CrowdloanRewards::ClaimedRelayChainIds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:1 w:1) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn associate_native_identity() -> Weight { + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `6172` + // Minimum execution time: 121_239_000 picoseconds. + Weight::from_parts(122_364_000, 6172) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `CrowdloanRewards::AccountsPayable` (r:2 w:2) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 500]`. + fn change_association_with_relay_keys(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `366 + x * (32 ±0)` + // Estimated: `6306 + x * (32 ±0)` + // Minimum execution time: 76_192_000 picoseconds. + Weight::from_parts(76_904_000, 6306) + // Standard Error: 10_191 + .saturating_add(Weight::from_parts(57_230_650, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(x.into())) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_evm.rs b/tracing/3100/runtime/common/src/weights/pallet_evm.rs new file mode 100644 index 00000000..e3aa76d1 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_evm.rs @@ -0,0 +1,80 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_evm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_evm +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_evm`. +pub struct WeightInfo(PhantomData); +impl pallet_evm::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:1 w:0) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 10000000]`. + fn runner_execute(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1574` + // Estimated: `7514` + // Minimum execution time: 23_399_294_000 picoseconds. + Weight::from_parts(23_731_883_576, 7514) + // Standard Error: 2 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + fn withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_641_000 picoseconds. + Weight::from_parts(1_773_000, 0) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_identity.rs b/tracing/3100/runtime/common/src/weights/pallet_identity.rs new file mode 100644 index 00000000..5a539788 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_identity.rs @@ -0,0 +1,411 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_identity` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_identity +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_identity`. +pub struct WeightInfo(PhantomData); +impl pallet_identity::WeightInfo for WeightInfo { + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn add_registrar(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 8_108_000 picoseconds. + Weight::from_parts(8_751_924, 2386) + // Standard Error: 1_419 + .saturating_add(Weight::from_parts(94_615, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn set_identity(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6966 + r * (5 ±0)` + // Estimated: `11025` + // Minimum execution time: 108_259_000 picoseconds. + Weight::from_parts(109_639_957, 11025) + // Standard Error: 3_282 + .saturating_add(Weight::from_parts(160_880, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:100 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 100]`. + fn set_subs_new(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `89` + // Estimated: `11025 + s * (2565 ±0)` + // Minimum execution time: 9_185_000 picoseconds. + Weight::from_parts(22_094_584, 11025) + // Standard Error: 5_122 + .saturating_add(Weight::from_parts(3_312_844, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_parts(0, 2565).saturating_mul(s.into())) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 100]`. + fn set_subs_old(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `169 + p * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 8_828_000 picoseconds. + Weight::from_parts(22_520_863, 11025) + // Standard Error: 3_232 + .saturating_add(Weight::from_parts(1_289_772, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + } + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + fn clear_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7046 + r * (5 ±0) + s * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 55_612_000 picoseconds. + Weight::from_parts(56_741_709, 11025) + // Standard Error: 8_881 + .saturating_add(Weight::from_parts(147_915, 0).saturating_mul(r.into())) + // Standard Error: 1_733 + .saturating_add(Weight::from_parts(1_281_887, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn request_judgement(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6956 + r * (45 ±0)` + // Estimated: `11025` + // Minimum execution time: 75_678_000 picoseconds. + Weight::from_parts(76_994_429, 11025) + // Standard Error: 3_106 + .saturating_add(Weight::from_parts(162_797, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn cancel_request(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6987` + // Estimated: `11025` + // Minimum execution time: 74_177_000 picoseconds. + Weight::from_parts(75_322_162, 11025) + // Standard Error: 2_566 + .saturating_add(Weight::from_parts(118_356, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_fee(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 6_146_000 picoseconds. + Weight::from_parts(6_470_417, 2386) + // Standard Error: 711 + .saturating_add(Weight::from_parts(71_623, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_account_id(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 6_119_000 picoseconds. + Weight::from_parts(6_370_315, 2386) + // Standard Error: 804 + .saturating_add(Weight::from_parts(71_772, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_fields(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 6_121_000 picoseconds. + Weight::from_parts(6_401_343, 2386) + // Standard Error: 698 + .saturating_add(Weight::from_parts(69_078, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn provide_judgement(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7022 + r * (45 ±0)` + // Estimated: `11025` + // Minimum execution time: 94_985_000 picoseconds. + Weight::from_parts(96_046_075, 11025) + // Standard Error: 2_953 + .saturating_add(Weight::from_parts(152_143, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + fn kill_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7436 + r * (5 ±0) + s * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 72_554_000 picoseconds. + Weight::from_parts(74_855_188, 11025) + // Standard Error: 7_528 + .saturating_add(Weight::from_parts(255_849, 0).saturating_mul(r.into())) + // Standard Error: 1_468 + .saturating_add(Weight::from_parts(1_295_109, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 99]`. + fn add_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `536 + s * (23 ±0)` + // Estimated: `11025` + // Minimum execution time: 26_599_000 picoseconds. + Weight::from_parts(30_890_978, 11025) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(72_723, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 100]`. + fn rename_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `615 + s * (4 ±0)` + // Estimated: `11025` + // Minimum execution time: 12_681_000 picoseconds. + Weight::from_parts(16_080_870, 11025) + // Standard Error: 1_356 + .saturating_add(Weight::from_parts(57_077, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 100]`. + fn remove_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `647 + s * (24 ±0)` + // Estimated: `11025` + // Minimum execution time: 30_291_000 picoseconds. + Weight::from_parts(34_880_904, 11025) + // Standard Error: 1_234 + .saturating_add(Weight::from_parts(89_267, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 99]`. + fn quit_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `620 + s * (24 ±0)` + // Estimated: `5511` + // Minimum execution time: 21_265_000 picoseconds. + Weight::from_parts(23_004_784, 5511) + // Standard Error: 1_350 + .saturating_add(Weight::from_parts(106_620, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn add_username_authority() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_860_000 picoseconds. + Weight::from_parts(6_134_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn remove_username_authority() -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `3505` + // Minimum execution time: 8_770_000 picoseconds. + Weight::from_parts(9_210_000, 3505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Identity::AccountOfUsername` (r:1 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::PendingUsernames` (r:1 w:0) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn set_username_for() -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `11025` + // Minimum execution time: 67_480_000 picoseconds. + Weight::from_parts(68_181_000, 11025) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Identity::PendingUsernames` (r:1 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::AccountOfUsername` (r:0 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + fn accept_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `11025` + // Minimum execution time: 20_259_000 picoseconds. + Weight::from_parts(20_652_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Identity::PendingUsernames` (r:1 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn remove_expired_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3538` + // Minimum execution time: 12_994_000 picoseconds. + Weight::from_parts(13_682_000, 3538) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::AccountOfUsername` (r:1 w:0) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn set_primary_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `232` + // Estimated: `11025` + // Minimum execution time: 16_070_000 picoseconds. + Weight::from_parts(16_462_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::AccountOfUsername` (r:1 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn remove_dangling_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `86` + // Estimated: `11025` + // Minimum execution time: 11_293_000 picoseconds. + Weight::from_parts(11_558_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs new file mode 100644 index 00000000..2daa581c --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs @@ -0,0 +1,173 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_foreign_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_foreign_assets +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_moonbeam_foreign_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_foreign_assets::WeightInfo for WeightInfo { + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::CounterForAssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::CounterForAssetsById` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:1) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:1) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:4 w:4) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::Suicided` (r:1 w:0) + /// Proof: `EVM::Suicided` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn create_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3272387` + // Estimated: `3283277` + // Minimum execution time: 3_610_969_000 picoseconds. + Weight::from_parts(3_661_242_000, 3283277) + .saturating_add(T::DbWeight::get().reads(19_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:2) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn change_xcm_location() -> Weight { + // Proof Size summary in bytes: + // Measured: `2020` + // Estimated: `5485` + // Minimum execution time: 41_219_000 picoseconds. + Weight::from_parts(43_570_000, 5485) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:0) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountStorages` (r:1 w:1) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn freeze_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3294569` + // Estimated: `3300509` + // Minimum execution time: 3_594_457_000 picoseconds. + Weight::from_parts(3_644_553_000, 3300509) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:0) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountStorages` (r:1 w:1) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn unfreeze_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3295628` + // Estimated: `3301568` + // Minimum execution time: 3_632_781_000 picoseconds. + Weight::from_parts(3_692_099_000, 3301568) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs new file mode 100644 index 00000000..63d83c8d --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs @@ -0,0 +1,77 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_lazy_migrations` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_lazy_migrations +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_moonbeam_lazy_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_lazy_migrations::WeightInfo for WeightInfo { + /// Storage: `EVM::Suicided` (r:100 w:0) + /// Proof: `EVM::Suicided` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodes` (r:100 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:1000 w:900) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamLazyMigrations::SuicidedContractsRemoved` (r:1 w:1) + /// Proof: `MoonbeamLazyMigrations::SuicidedContractsRemoved` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `a` is `[1, 100]`. + /// The range of component `l` is `[1, 1000]`. + fn clear_suicided_storage(a: u32, l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4251 + a * (12 ±0) + l * (84 ±0)` + // Estimated: `37759 + a * (2229 ±19) + l * (2536 ±1)` + // Minimum execution time: 46_475_000 picoseconds. + Weight::from_parts(47_461_000, 37759) + // Standard Error: 2_615_231 + .saturating_add(Weight::from_parts(42_043_431, 0).saturating_mul(a.into())) + // Standard Error: 261_244 + .saturating_add(Weight::from_parts(27_225_099, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(l.into()))) + .saturating_add(T::DbWeight::get().writes(41_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(l.into()))) + .saturating_add(Weight::from_parts(0, 2229).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2536).saturating_mul(l.into())) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_moonbeam_orbiters.rs b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_orbiters.rs new file mode 100644 index 00000000..9d78e06f --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_moonbeam_orbiters.rs @@ -0,0 +1,203 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_orbiters` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_orbiters +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_moonbeam_orbiters`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_orbiters::WeightInfo for WeightInfo { + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:0) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + fn collator_add_orbiter() -> Weight { + // Proof Size summary in bytes: + // Measured: `562` + // Estimated: `4502` + // Minimum execution time: 19_995_000 picoseconds. + Weight::from_parts(20_494_000, 4502) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn collator_remove_orbiter() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 15_754_000 picoseconds. + Weight::from_parts(16_206_000, 3831) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn orbiter_leave_collator_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 15_482_000 picoseconds. + Weight::from_parts(16_307_000, 3831) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::MinOrbiterDeposit` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::MinOrbiterDeposit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::RegisteredOrbiter` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::RegisteredOrbiter` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn orbiter_register() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `4502` + // Minimum execution time: 29_243_000 picoseconds. + Weight::from_parts(29_784_000, 4502) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:101 w:0) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::RegisteredOrbiter` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::RegisteredOrbiter` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `n` is `[0, 100]`. + fn orbiter_unregister(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `391 + n * (48 ±0)` + // Estimated: `4502 + n * (2524 ±0)` + // Minimum execution time: 36_986_000 picoseconds. + Weight::from_parts(36_846_044, 4502) + // Standard Error: 9_375 + .saturating_add(Weight::from_parts(7_211_237, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 2524).saturating_mul(n.into())) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn add_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 10_383_000 picoseconds. + Weight::from_parts(10_738_000, 3547) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::AccountLookupOverride` (r:0 w:9) + /// Proof: `MoonbeamOrbiters::AccountLookupOverride` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 22_406_000 picoseconds. + Weight::from_parts(23_437_000, 3831) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) + } + /// Storage: `MoonbeamOrbiters::CurrentRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::CurrentRound` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:100 w:100) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 100]`. + fn on_initialize(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `140 + x * (61 ±0)` + // Estimated: `1624 + x * (2537 ±0)` + // Minimum execution time: 6_670_000 picoseconds. + Weight::from_parts(6_354_039, 1624) + // Standard Error: 1_300 + .saturating_add(Weight::from_parts(859_066, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 2537).saturating_mul(x.into())) + } + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn distribute_rewards() -> Weight { + // Proof Size summary in bytes: + // Measured: `298` + // Estimated: `3763` + // Minimum execution time: 20_884_000 picoseconds. + Weight::from_parts(21_482_000, 3763) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MoonbeamOrbiters::ForceRotation` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::ForceRotation` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:2 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:0 w:3) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::AccountLookupOverride` (r:0 w:3) + /// Proof: `MoonbeamOrbiters::AccountLookupOverride` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CurrentRound` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::CurrentRound` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_new_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6196` + // Minimum execution time: 29_827_000 picoseconds. + Weight::from_parts(30_796_000, 6196) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_multisig.rs b/tracing/3100/runtime/common/src/weights/pallet_multisig.rs new file mode 100644 index 00000000..62fea842 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_multisig.rs @@ -0,0 +1,160 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_multisig` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_multisig +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_multisig`. +pub struct WeightInfo(PhantomData); +impl pallet_multisig::WeightInfo for WeightInfo { + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 14_560_000 picoseconds. + Weight::from_parts(15_671_303, 1527) + // Standard Error: 3 + .saturating_add(Weight::from_parts(497, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_create(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `5587` + // Minimum execution time: 41_116_000 picoseconds. + Weight::from_parts(30_831_924, 5587) + // Standard Error: 721 + .saturating_add(Weight::from_parts(113_207, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_432, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `5587` + // Minimum execution time: 25_384_000 picoseconds. + Weight::from_parts(16_994_914, 5587) + // Standard Error: 352 + .saturating_add(Weight::from_parts(97_428, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_419, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `475 + s * (20 ±0)` + // Estimated: `5587 + s * (20 ±0)` + // Minimum execution time: 49_663_000 picoseconds. + Weight::from_parts(37_045_018, 5587) + // Standard Error: 822 + .saturating_add(Weight::from_parts(138_891, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_469, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(s.into())) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_create(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `5587` + // Minimum execution time: 28_254_000 picoseconds. + Weight::from_parts(29_089_033, 5587) + // Standard Error: 653 + .saturating_add(Weight::from_parts(115_512, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_approve(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `5587` + // Minimum execution time: 14_998_000 picoseconds. + Weight::from_parts(15_446_556, 5587) + // Standard Error: 424 + .saturating_add(Weight::from_parts(98_015, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn cancel_as_multi(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5587` + // Minimum execution time: 29_901_000 picoseconds. + Weight::from_parts(30_620_256, 5587) + // Standard Error: 610 + .saturating_add(Weight::from_parts(108_307, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_parachain_staking.rs b/tracing/3100/runtime/common/src/weights/pallet_parachain_staking.rs new file mode 100644 index 00000000..858b22ac --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_parachain_staking.rs @@ -0,0 +1,864 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_parachain_staking` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_parachain_staking +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_parachain_staking`. +pub struct WeightInfo(PhantomData); +impl pallet_parachain_staking::WeightInfo for WeightInfo { + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_staking_expectations() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 7_828_000 picoseconds. + Weight::from_parts(8_047_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_inflation() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 35_957_000 picoseconds. + Weight::from_parts(36_236_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::ParachainBondInfo` (r:1 w:1) + /// Proof: `ParachainStaking::ParachainBondInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_parachain_bond_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `7` + // Estimated: `1492` + // Minimum execution time: 6_433_000 picoseconds. + Weight::from_parts(6_817_000, 1492) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::ParachainBondInfo` (r:1 w:1) + /// Proof: `ParachainStaking::ParachainBondInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_parachain_bond_reserve_percent() -> Weight { + // Proof Size summary in bytes: + // Measured: `7` + // Estimated: `1492` + // Minimum execution time: 6_320_000 picoseconds. + Weight::from_parts(6_587_000, 1492) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:1) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_total_selected() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `1513` + // Minimum execution time: 7_177_000 picoseconds. + Weight::from_parts(7_418_000, 1513) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CollatorCommission` (r:1 w:1) + /// Proof: `ParachainStaking::CollatorCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_collator_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `27` + // Estimated: `1512` + // Minimum execution time: 6_471_000 picoseconds. + Weight::from_parts(6_875_000, 1512) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_blocks_per_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `116` + // Estimated: `1601` + // Minimum execution time: 37_896_000 picoseconds. + Weight::from_parts(38_490_000, 1601) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:0) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:0 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:0 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn join_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1417 + x * (38 ±0)` + // Estimated: `4752 + x * (41 ±0)` + // Minimum execution time: 45_656_000 picoseconds. + Weight::from_parts(55_894_334, 4752) + // Standard Error: 1_811 + .saturating_add(Weight::from_parts(86_659, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 41).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn schedule_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `665 + x * (37 ±0)` + // Estimated: `4023 + x * (38 ±0)` + // Minimum execution time: 15_044_000 picoseconds. + Weight::from_parts(20_441_432, 4023) + // Standard Error: 942 + .saturating_add(Weight::from_parts(60_562, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 38).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:350 w:350) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:350 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:350 w:350) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[2, 350]`. + fn execute_leave_candidates_worst_case(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1700 + x * (431 ±0)` + // Estimated: `4948 + x * (3762 ±0)` + // Minimum execution time: 95_358_000 picoseconds. + Weight::from_parts(96_663_000, 4948) + // Standard Error: 72_339 + .saturating_add(Weight::from_parts(34_050_382, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3762).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:350 w:350) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:350 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:350 w:350) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[2, 350]`. + /// The range of component `y` is `[2, 350]`. + fn execute_leave_candidates_ideal(x: u32, _y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1695 + x * (431 ±0)` + // Estimated: `4907 + x * (3762 ±0)` + // Minimum execution time: 86_669_000 picoseconds. + Weight::from_parts(88_888_000, 4907) + // Standard Error: 30_058 + .saturating_add(Weight::from_parts(35_545_550, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3762).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn cancel_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `633 + x * (37 ±0)` + // Estimated: `3991 + x * (38 ±0)` + // Minimum execution time: 14_473_000 picoseconds. + Weight::from_parts(19_839_811, 3991) + // Standard Error: 925 + .saturating_add(Weight::from_parts(60_750, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 38).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn go_offline(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `530 + x * (38 ±0)` + // Estimated: `3931 + x * (39 ±0)` + // Minimum execution time: 14_177_000 picoseconds. + Weight::from_parts(19_022_914, 3931) + // Standard Error: 1_028 + .saturating_add(Weight::from_parts(62_692, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn go_online(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `494 + x * (38 ±0)` + // Estimated: `3895 + x * (39 ±0)` + // Minimum execution time: 13_665_000 picoseconds. + Weight::from_parts(18_925_154, 3895) + // Standard Error: 1_023 + .saturating_add(Weight::from_parts(63_066, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn candidate_bond_more(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1233 + x * (42 ±0)` + // Estimated: `4752 + x * (44 ±0)` + // Minimum execution time: 40_631_000 picoseconds. + Weight::from_parts(49_950_003, 4752) + // Standard Error: 1_822 + .saturating_add(Weight::from_parts(88_012, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 44).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn schedule_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3636` + // Minimum execution time: 12_094_000 picoseconds. + Weight::from_parts(12_413_000, 3636) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn execute_candidate_bond_less(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1322 + x * (42 ±0)` + // Estimated: `4752 + x * (43 ±0)` + // Minimum execution time: 43_944_000 picoseconds. + Weight::from_parts(51_365_396, 4752) + // Standard Error: 1_158 + .saturating_add(Weight::from_parts(73_667, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn set_candidate_bond_to_zero(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1302 + x * (42 ±0)` + // Estimated: `4752 + x * (43 ±0)` + // Minimum execution time: 41_062_000 picoseconds. + Weight::from_parts(47_815_494, 4752) + // Standard Error: 1_095 + .saturating_add(Weight::from_parts(67_457, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn cancel_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `191` + // Estimated: `3656` + // Minimum execution time: 11_211_000 picoseconds. + Weight::from_parts(11_743_000, 3656) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 100]`. + /// The range of component `y` is `[2, 300]`. + fn delegate(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2461 + x * (79 ±0) + y * (38 ±0)` + // Estimated: `5710 + x * (81 ±0) + y * (39 ±0)` + // Minimum execution time: 87_435_000 picoseconds. + Weight::from_parts(78_725_858, 5710) + // Standard Error: 1_499 + .saturating_add(Weight::from_parts(142_369, 0).saturating_mul(x.into())) + // Standard Error: 491 + .saturating_add(Weight::from_parts(43_629, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 81).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(y.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn schedule_revoke_delegation(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `567 + x * (42 ±0)` + // Estimated: `4013 + x * (43 ±0)` + // Minimum execution time: 15_133_000 picoseconds. + Weight::from_parts(22_339_126, 4013) + // Standard Error: 694 + .saturating_add(Weight::from_parts(64_852, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn delegator_bond_more(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2016 + x * (79 ±0)` + // Estimated: `5438 + x * (79 ±0)` + // Minimum execution time: 59_312_000 picoseconds. + Weight::from_parts(76_036_635, 5438) + // Standard Error: 1_416 + .saturating_add(Weight::from_parts(105_129, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 79).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn schedule_delegator_bond_less(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `567 + x * (42 ±0)` + // Estimated: `4013 + x * (43 ±0)` + // Minimum execution time: 15_664_000 picoseconds. + Weight::from_parts(22_554_084, 4013) + // Standard Error: 665 + .saturating_add(Weight::from_parts(65_530, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:0) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `998` + // Estimated: `4752` + // Minimum execution time: 70_078_000 picoseconds. + Weight::from_parts(72_265_000, 4752) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_delegator_revoke_delegation_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `37342` + // Estimated: `40807` + // Minimum execution time: 131_495_000 picoseconds. + Weight::from_parts(132_932_000, 40807) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_delegator_bond_less_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `29964` + // Estimated: `33429` + // Minimum execution time: 113_183_000 picoseconds. + Weight::from_parts(115_008_000, 33429) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn cancel_delegation_request(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `664 + x * (42 ±0)` + // Estimated: `4093 + x * (43 ±0)` + // Minimum execution time: 18_997_000 picoseconds. + Weight::from_parts(26_942_592, 4093) + // Standard Error: 675 + .saturating_add(Weight::from_parts(54_069, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::Points` (r:1 w:0) + /// Proof: `ParachainStaking::Points` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn prepare_staking_payouts() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3468` + // Minimum execution time: 2_780_000 picoseconds. + Weight::from_parts(2_940_000, 3468) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:0) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `y` is `[0, 100]`. + fn get_rewardable_delegators(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73 + y * (36 ±0)` + // Estimated: `3537 + y * (36 ±0)` + // Minimum execution time: 6_149_000 picoseconds. + Weight::from_parts(7_528_114, 3537) + // Standard Error: 585 + .saturating_add(Weight::from_parts(50_092, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(y.into())) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:0) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:51 w:0) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:51 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:51 w:0) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:51 w:0) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:0 w:1) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:0 w:51) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 50]`. + /// The range of component `y` is `[0, 100]`. + fn select_top_candidates(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (3816 ±0) + y * (1800 ±0)` + // Estimated: `3693 + x * (3975 ±39) + y * (639 ±19)` + // Minimum execution time: 19_254_000 picoseconds. + Weight::from_parts(19_539_000, 3693) + // Standard Error: 71_994 + .saturating_add(Weight::from_parts(15_542_966, 0).saturating_mul(x.into())) + // Standard Error: 35_901 + .saturating_add(Weight::from_parts(1_181_056, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3975).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 639).saturating_mul(y.into())) + } + /// Storage: `System::Account` (r:349 w:349) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:349 w:349) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:349 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + /// The range of component `y` is `[0, 349]`. + /// The range of component `z` is `[0, 349]`. + fn pay_one_collator_reward_best(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (396 ±0) + y * (156 ±0) + z * (41 ±0)` + // Estimated: `126467 + x * (2591 ±0) + y * (2234 ±19) + z * (28 ±0)` + // Minimum execution time: 184_000 picoseconds. + Weight::from_parts(202_000, 126467) + // Standard Error: 503_738 + .saturating_add(Weight::from_parts(47_312_340, 0).saturating_mul(x.into())) + // Standard Error: 503_738 + .saturating_add(Weight::from_parts(28_945_643, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2234).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(z.into())) + } + /// Storage: `ParachainStaking::DelayedPayouts` (r:1 w:0) + /// Proof: `ParachainStaking::DelayedPayouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Points` (r:1 w:0) + /// Proof: `ParachainStaking::Points` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:2 w:1) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AwardedPts` (r:1 w:1) + /// Proof: `ParachainStaking::AwardedPts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:301 w:301) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `y` is `[0, 300]`. + fn pay_one_collator_reward(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1764 + y * (161 ±0)` + // Estimated: `7437 + y * (2591 ±0)` + // Minimum execution time: 46_317_000 picoseconds. + Weight::from_parts(45_428_324, 7437) + // Standard Error: 4_865 + .saturating_add(Weight::from_parts(13_681_741, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(y.into())) + } + fn base_on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 617_000 picoseconds. + Weight::from_parts(659_000, 0) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:0) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 300]`. + /// The range of component `y` is `[0, 100]`. + fn set_auto_compound(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `672 + x * (22 ±0) + y * (36 ±0)` + // Estimated: `4028 + x * (23 ±0) + y * (36 ±0)` + // Minimum execution time: 23_264_000 picoseconds. + Weight::from_parts(23_616_866, 4028) + // Standard Error: 405 + .saturating_add(Weight::from_parts(40_193, 0).saturating_mul(x.into())) + // Standard Error: 1_214 + .saturating_add(Weight::from_parts(39_826, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 23).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(y.into())) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 350]`. + /// The range of component `y` is `[0, 349]`. + /// The range of component `z` is `[0, 99]`. + fn delegate_with_auto_compound(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (60 ±0) + y * (21 ±0) + z * (78 ±0)` + // Estimated: `26250 + x * (44 ±0) + y * (19 ±0) + z * (76 ±1)` + // Minimum execution time: 94_324_000 picoseconds. + Weight::from_parts(79_124_741, 26250) + // Standard Error: 948 + .saturating_add(Weight::from_parts(108_997, 0).saturating_mul(x.into())) + // Standard Error: 3_349 + .saturating_add(Weight::from_parts(182_679, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_parts(0, 44).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 19).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 76).saturating_mul(z.into())) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:2 w:2) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:2 w:2) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn delegate_with_auto_compound_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `48131` + // Estimated: `54071` + // Minimum execution time: 210_196_000 picoseconds. + Weight::from_parts(213_174_000, 54071) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn mint_collator_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `128` + // Estimated: `3581` + // Minimum execution time: 15_313_000 picoseconds. + Weight::from_parts(15_692_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::EnableMarkingOffline` (r:1 w:0) + /// Proof: `ParachainStaking::EnableMarkingOffline` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:1 w:0) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:2 w:0) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AwardedPts` (r:2 w:0) + /// Proof: `ParachainStaking::AwardedPts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_inactive_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `11566` + // Estimated: `17506` + // Minimum execution time: 67_162_000 picoseconds. + Weight::from_parts(69_272_000, 17506) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_precompile_benchmarks.rs b/tracing/3100/runtime/common/src/weights/pallet_precompile_benchmarks.rs new file mode 100644 index 00000000..c0d79711 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_precompile_benchmarks.rs @@ -0,0 +1,80 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_precompile_benchmarks` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_precompile_benchmarks +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_precompile_benchmarks`. +pub struct WeightInfo(PhantomData); +impl pallet_precompile_benchmarks::WeightInfo for WeightInfo { + /// The range of component `x` is `[100, 2000]`. + fn verify_entry(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 75_987_000 picoseconds. + Weight::from_parts(76_430_000, 0) + // Standard Error: 2_418 + .saturating_add(Weight::from_parts(678_469, 0).saturating_mul(x.into())) + } + /// Storage: `RelayStorageRoots::RelayStorageRootKeys` (r:1 w:0) + /// Proof: `RelayStorageRoots::RelayStorageRootKeys` (`max_values`: Some(1), `max_size`: Some(121), added: 616, mode: `MaxEncodedLen`) + fn latest_relay_block() -> Weight { + // Proof Size summary in bytes: + // Measured: `227` + // Estimated: `1606` + // Minimum execution time: 4_434_000 picoseconds. + Weight::from_parts(4_641_000, 1606) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn p256_verify() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_572_623_000 picoseconds. + Weight::from_parts(1_580_914_000, 0) + // TODO: Remove this multiplication once we are comfortable with the weight estimation + // Double the weight just to mitigate the possibility of having a signature that + // takes longer to verify + .saturating_mul(1u64) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_preimage.rs b/tracing/3100/runtime/common/src/weights/pallet_preimage.rs new file mode 100644 index 00000000..50bad336 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_preimage.rs @@ -0,0 +1,251 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_preimage` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_preimage`. +pub struct WeightInfo(PhantomData); +impl pallet_preimage::WeightInfo for WeightInfo { + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3544` + // Minimum execution time: 45_177_000 picoseconds. + Weight::from_parts(45_594_000, 3544) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_277, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_requested_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 14_526_000 picoseconds. + Weight::from_parts(14_719_000, 3544) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_258, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_no_deposit_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 13_789_000 picoseconds. + Weight::from_parts(14_101_000, 3544) + // Standard Error: 4 + .saturating_add(Weight::from_parts(2_256, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unnote_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `220` + // Estimated: `3544` + // Minimum execution time: 49_292_000 picoseconds. + Weight::from_parts(50_686_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unnote_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 21_709_000 picoseconds. + Weight::from_parts(22_129_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `176` + // Estimated: `3544` + // Minimum execution time: 18_304_000 picoseconds. + Weight::from_parts(18_617_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 13_020_000 picoseconds. + Weight::from_parts(13_345_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3544` + // Minimum execution time: 14_348_000 picoseconds. + Weight::from_parts(14_980_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_requested_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 9_835_000 picoseconds. + Weight::from_parts(10_133_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unrequest_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 19_003_000 picoseconds. + Weight::from_parts(19_228_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn unrequest_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 9_935_000 picoseconds. + Weight::from_parts(10_081_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn unrequest_multi_referenced_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 9_788_000 picoseconds. + Weight::from_parts(10_021_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1023 w:1023) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1023 w:1023) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1024]`. + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1461 + n * (203 ±0)` + // Estimated: `990 + n * (2591 ±0)` + // Minimum execution time: 53_161_000 picoseconds. + Weight::from_parts(53_977_000, 990) + // Standard Error: 32_285 + .saturating_add(Weight::from_parts(52_668_948, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(n.into())) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_proxy.rs b/tracing/3100/runtime/common/src/weights/pallet_proxy.rs new file mode 100644 index 00000000..5ad6dc3b --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_proxy.rs @@ -0,0 +1,217 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_proxy +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `191 + p * (25 ±0)` + // Estimated: `4310 + p * (25 ±0)` + // Minimum execution time: 14_347_000 picoseconds. + Weight::from_parts(15_000_069, 4310) + // Standard Error: 1_007 + .saturating_add(Weight::from_parts(29_390, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 25).saturating_mul(p.into())) + // 1 DB read that happen when filtering the proxy call transaction + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `443 + a * (56 ±0) + p * (25 ±0)` + // Estimated: `5302 + a * (60 ±0) + p * (22 ±0)` + // Minimum execution time: 37_293_000 picoseconds. + Weight::from_parts(38_057_374, 5302) + // Standard Error: 2_239 + .saturating_add(Weight::from_parts(148_897, 0).saturating_mul(a.into())) + // Standard Error: 2_314 + .saturating_add(Weight::from_parts(15_570, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 22).saturating_mul(p.into())) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, _p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `329 + a * (56 ±0)` + // Estimated: `5302` + // Minimum execution time: 21_475_000 picoseconds. + Weight::from_parts(23_085_318, 5302) + // Standard Error: 5_183 + .saturating_add(Weight::from_parts(164_563, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, _p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `329 + a * (56 ±0)` + // Estimated: `5302` + // Minimum execution time: 21_462_000 picoseconds. + Weight::from_parts(22_842_470, 5302) + // Standard Error: 5_185 + .saturating_add(Weight::from_parts(167_973, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `345 + a * (56 ±0) + p * (25 ±0)` + // Estimated: `5302` + // Minimum execution time: 29_252_000 picoseconds. + Weight::from_parts(31_567_840, 5302) + // Standard Error: 2_347 + .saturating_add(Weight::from_parts(167_939, 0).saturating_mul(a.into())) + // Standard Error: 2_425 + .saturating_add(Weight::from_parts(23_302, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 21_330_000 picoseconds. + Weight::from_parts(22_137_571, 4310) + // Standard Error: 1_077 + .saturating_add(Weight::from_parts(32_996, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 20_850_000 picoseconds. + Weight::from_parts(22_084_183, 4310) + // Standard Error: 1_645 + .saturating_add(Weight::from_parts(39_583, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 20_495_000 picoseconds. + Weight::from_parts(21_284_220, 4310) + // Standard Error: 1_053 + .saturating_add(Weight::from_parts(35_054, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `4310` + // Minimum execution time: 22_713_000 picoseconds. + Weight::from_parts(23_735_612, 4310) + // Standard Error: 1_011 + .saturating_add(Weight::from_parts(5_249, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 21_389_000 picoseconds. + Weight::from_parts(22_106_540, 4310) + // Standard Error: 989 + .saturating_add(Weight::from_parts(27_748, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_randomness.rs b/tracing/3100/runtime/common/src/weights/pallet_randomness.rs new file mode 100644 index 00000000..48757203 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_randomness.rs @@ -0,0 +1,162 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_randomness` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_randomness +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_randomness`. +pub struct WeightInfo(PhantomData); +impl pallet_randomness::WeightInfo for WeightInfo { + /// Storage: `Randomness::RelayEpoch` (r:1 w:1) + /// Proof: `Randomness::RelayEpoch` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelayStateProof` (r:1 w:0) + /// Proof: `ParachainSystem::RelayStateProof` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::InherentIncluded` (r:0 w:1) + /// Proof: `Randomness::InherentIncluded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_babe_randomness_results() -> Weight { + // Proof Size summary in bytes: + // Measured: `297` + // Estimated: `3762` + // Minimum execution time: 12_337_000 picoseconds. + Weight::from_parts(12_868_000, 3762) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Randomness::NotFirstBlock` (r:1 w:0) + /// Proof: `Randomness::NotFirstBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:0) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::LocalVrfOutput` (r:1 w:1) + /// Proof: `Randomness::LocalVrfOutput` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `719` + // Estimated: `4184` + // Minimum execution time: 512_947_000 picoseconds. + Weight::from_parts(515_352_000, 4184) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Randomness::RequestCount` (r:1 w:1) + /// Proof: `Randomness::RequestCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::Requests` (r:0 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn request_randomness() -> Weight { + // Proof Size summary in bytes: + // Measured: `549` + // Estimated: `6172` + // Minimum execution time: 49_498_000 picoseconds. + Weight::from_parts(50_245_000, 6172) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:0) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:0) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 100]`. + fn prepare_fulfillment(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `3877` + // Minimum execution time: 9_202_000 picoseconds. + Weight::from_parts(9_784_794, 3877) + // Standard Error: 308 + .saturating_add(Weight::from_parts(257_364, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::Requests` (r:0 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn finish_fulfillment() -> Weight { + // Proof Size summary in bytes: + // Measured: `739` + // Estimated: `6172` + // Minimum execution time: 46_724_000 picoseconds. + Weight::from_parts(47_652_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn increase_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `825` + // Estimated: `6172` + // Minimum execution time: 46_455_000 picoseconds. + Weight::from_parts(47_560_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_request_expiration() -> Weight { + // Proof Size summary in bytes: + // Measured: `868` + // Estimated: `6172` + // Minimum execution time: 50_507_000 picoseconds. + Weight::from_parts(51_796_000, 6172) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_referenda.rs b/tracing/3100/runtime/common/src/weights/pallet_referenda.rs new file mode 100644 index 00000000..55be5ec9 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_referenda.rs @@ -0,0 +1,483 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_referenda` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_referenda +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_referenda`. +pub struct WeightInfo(PhantomData); +impl pallet_referenda::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumCount` (r:1 w:1) + /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `269` + // Estimated: `42428` + // Minimum execution time: 31_284_000 picoseconds. + Weight::from_parts(32_095_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 42_378_000 picoseconds. + Weight::from_parts(43_528_000, 83866) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3303` + // Estimated: `42428` + // Minimum execution time: 59_751_000 picoseconds. + Weight::from_parts(61_840_000, 42428) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3323` + // Estimated: `42428` + // Minimum execution time: 59_169_000 picoseconds. + Weight::from_parts(61_392_000, 42428) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 52_076_000 picoseconds. + Weight::from_parts(53_544_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 48_391_000 picoseconds. + Weight::from_parts(49_300_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn refund_decision_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `4377` + // Minimum execution time: 26_732_000 picoseconds. + Weight::from_parts(27_598_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn refund_submission_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `378` + // Estimated: `4377` + // Minimum execution time: 26_082_000 picoseconds. + Weight::from_parts(26_760_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `83866` + // Minimum execution time: 29_322_000 picoseconds. + Weight::from_parts(29_727_000, 83866) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:0) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `1007` + // Estimated: `83866` + // Minimum execution time: 91_127_000 picoseconds. + Weight::from_parts(93_012_000, 83866) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:0) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + fn one_fewer_deciding_queue_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `5477` + // Minimum execution time: 9_080_000 picoseconds. + Weight::from_parts(9_344_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3090` + // Estimated: `42428` + // Minimum execution time: 40_824_000 picoseconds. + Weight::from_parts(42_162_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3090` + // Estimated: `42428` + // Minimum execution time: 42_882_000 picoseconds. + Weight::from_parts(44_241_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_insertion() -> Weight { + // Proof Size summary in bytes: + // Measured: `2915` + // Estimated: `5477` + // Minimum execution time: 22_878_000 picoseconds. + Weight::from_parts(23_708_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_slide() -> Weight { + // Proof Size summary in bytes: + // Measured: `2915` + // Estimated: `5477` + // Minimum execution time: 22_531_000 picoseconds. + Weight::from_parts(23_436_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2919` + // Estimated: `5477` + // Minimum execution time: 27_188_000 picoseconds. + Weight::from_parts(28_163_000, 5477) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2939` + // Estimated: `5477` + // Minimum execution time: 27_257_000 picoseconds. + Weight::from_parts(28_190_000, 5477) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `249` + // Estimated: `42428` + // Minimum execution time: 18_433_000 picoseconds. + Weight::from_parts(18_986_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 18_919_000 picoseconds. + Weight::from_parts(19_491_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn nudge_referendum_timed_out() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `4377` + // Minimum execution time: 11_910_000 picoseconds. + Weight::from_parts(12_360_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 24_362_000 picoseconds. + Weight::from_parts(25_525_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 26_306_000 picoseconds. + Weight::from_parts(26_937_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 21_742_000 picoseconds. + Weight::from_parts(22_303_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `321` + // Estimated: `42428` + // Minimum execution time: 21_577_000 picoseconds. + Weight::from_parts(22_318_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 20_547_000 picoseconds. + Weight::from_parts(21_091_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `342` + // Estimated: `42428` + // Minimum execution time: 19_986_000 picoseconds. + Weight::from_parts(20_640_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn nudge_referendum_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `342` + // Estimated: `83866` + // Minimum execution time: 31_226_000 picoseconds. + Weight::from_parts(32_003_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 21_947_000 picoseconds. + Weight::from_parts(22_270_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:0 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `4377` + // Minimum execution time: 17_958_000 picoseconds. + Weight::from_parts(18_248_000, 4377) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `271` + // Estimated: `4377` + // Minimum execution time: 13_888_000 picoseconds. + Weight::from_parts(14_537_000, 4377) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_relay_storage_roots.rs b/tracing/3100/runtime/common/src/weights/pallet_relay_storage_roots.rs new file mode 100644 index 00000000..609cdf97 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_relay_storage_roots.rs @@ -0,0 +1,64 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_relay_storage_roots` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_relay_storage_roots +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_relay_storage_roots`. +pub struct WeightInfo(PhantomData); +impl pallet_relay_storage_roots::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `RelayStorageRoots::RelayStorageRoot` (r:1 w:2) + /// Proof: `RelayStorageRoots::RelayStorageRoot` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `RelayStorageRoots::RelayStorageRootKeys` (r:1 w:1) + /// Proof: `RelayStorageRoots::RelayStorageRootKeys` (`max_values`: Some(1), `max_size`: Some(121), added: 616, mode: `MaxEncodedLen`) + fn set_relay_storage_root() -> Weight { + // Proof Size summary in bytes: + // Measured: `972` + // Estimated: `3509` + // Minimum execution time: 17_270_000 picoseconds. + Weight::from_parts(17_907_000, 3509) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_scheduler.rs b/tracing/3100/runtime/common/src/weights/pallet_scheduler.rs new file mode 100644 index 00000000..ffec8c0b --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_scheduler.rs @@ -0,0 +1,272 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_scheduler` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_scheduler +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_scheduler`. +pub struct WeightInfo(PhantomData); +impl pallet_scheduler::WeightInfo for WeightInfo { + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn service_agendas_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `31` + // Estimated: `1489` + // Minimum execution time: 2_808_000 picoseconds. + Weight::from_parts(2_968_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 50]`. + fn service_agenda_base(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 3_544_000 picoseconds. + Weight::from_parts(6_382_107, 42428) + // Standard Error: 1_506 + .saturating_add(Weight::from_parts(347_913, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn service_task_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_145_000 picoseconds. + Weight::from_parts(3_277_000, 0) + } + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `179 + s * (1 ±0)` + // Estimated: `3644 + s * (1 ±0)` + // Minimum execution time: 16_999_000 picoseconds. + Weight::from_parts(17_237_000, 3644) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_149, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) + } + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn service_task_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_374_000 picoseconds. + Weight::from_parts(4_654_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn service_task_periodic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_094_000 picoseconds. + Weight::from_parts(3_228_000, 0) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_dispatch_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_172_000 picoseconds. + Weight::from_parts(4_308_000, 1527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn execute_dispatch_unsigned() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_871_000 picoseconds. + Weight::from_parts(1_989_000, 0) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 49]`. + fn schedule(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 9_595_000 picoseconds. + Weight::from_parts(12_319_227, 42428) + // Standard Error: 1_376 + .saturating_add(Weight::from_parts(376_990, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn cancel(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 14_867_000 picoseconds. + Weight::from_parts(14_542_096, 42428) + // Standard Error: 1_032 + .saturating_add(Weight::from_parts(572_005, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 49]`. + fn schedule_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `255 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 13_069_000 picoseconds. + Weight::from_parts(16_438_564, 42428) + // Standard Error: 2_235 + .saturating_add(Weight::from_parts(409_569, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn cancel_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `281 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 17_074_000 picoseconds. + Weight::from_parts(17_547_084, 42428) + // Standard Error: 1_676 + .saturating_add(Weight::from_parts(601_393, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `42428` + // Minimum execution time: 8_729_000 picoseconds. + Weight::from_parts(9_160_109, 42428) + // Standard Error: 455 + .saturating_add(Weight::from_parts(27_735, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8928` + // Estimated: `42428` + // Minimum execution time: 23_949_000 picoseconds. + Weight::from_parts(24_636_000, 42428) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9606` + // Estimated: `42428` + // Minimum execution time: 28_469_000 picoseconds. + Weight::from_parts(29_831_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8940` + // Estimated: `42428` + // Minimum execution time: 22_708_000 picoseconds. + Weight::from_parts(23_679_000, 42428) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9618` + // Estimated: `42428` + // Minimum execution time: 28_825_000 picoseconds. + Weight::from_parts(29_550_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_sudo.rs b/tracing/3100/runtime/common/src/weights/pallet_sudo.rs new file mode 100644 index 00000000..bf3e95e6 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_sudo.rs @@ -0,0 +1,91 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_sudo` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_sudo +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_sudo`. +pub struct WeightInfo(PhantomData); +impl pallet_sudo::WeightInfo for WeightInfo { + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn set_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 8_485_000 picoseconds. + Weight::from_parts(8_731_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn sudo() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 9_300_000 picoseconds. + Weight::from_parts(9_558_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn sudo_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 9_183_000 picoseconds. + Weight::from_parts(9_639_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 7_629_000 picoseconds. + Weight::from_parts(8_047_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_timestamp.rs b/tracing/3100/runtime/common/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000..0c274a52 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_timestamp.rs @@ -0,0 +1,67 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_timestamp` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_timestamp +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `1493` + // Minimum execution time: 4_336_000 picoseconds. + Weight::from_parts(4_620_000, 1493) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `57` + // Estimated: `0` + // Minimum execution time: 3_051_000 picoseconds. + Weight::from_parts(3_185_000, 0) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_treasury.rs b/tracing/3100/runtime/common/src/weights/pallet_treasury.rs new file mode 100644 index 00000000..55808994 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_treasury.rs @@ -0,0 +1,189 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_treasury +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_treasury`. +pub struct WeightInfo(PhantomData); +impl pallet_treasury::WeightInfo for WeightInfo { + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn spend_local() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1887` + // Minimum execution time: 11_011_000 picoseconds. + Weight::from_parts(11_357_000, 1887) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn propose_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `1489` + // Minimum execution time: 24_794_000 picoseconds. + Weight::from_parts(25_297_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Treasury::Proposals` (r:1 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn reject_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `775` + // Estimated: `6172` + // Minimum execution time: 41_889_000 picoseconds. + Weight::from_parts(43_202_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::Proposals` (r:1 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn approve_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `608 + p * (8 ±0)` + // Estimated: `3549` + // Minimum execution time: 8_549_000 picoseconds. + Weight::from_parts(11_280_655, 3549) + // Standard Error: 1_499 + .saturating_add(Weight::from_parts(84_828, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn remove_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `265` + // Estimated: `1887` + // Minimum execution time: 6_727_000 picoseconds. + Weight::from_parts(6_885_000, 1887) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Deactivated` (r:1 w:1) + /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:1) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:99 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `389 + p * (97 ±0)` + // Estimated: `3581 + p * (2559 ±0)` + // Minimum execution time: 19_161_000 picoseconds. + Weight::from_parts(19_547_872, 3581) + // Standard Error: 7_358 + .saturating_add(Weight::from_parts(3_295_908, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 2559).saturating_mul(p.into())) + } + /// Storage: `Treasury::SpendCount` (r:1 w:1) + /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Spends` (r:0 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1489` + // Minimum execution time: 9_894_000 picoseconds. + Weight::from_parts(10_234_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `586` + // Estimated: `6172` + // Minimum execution time: 49_489_000 picoseconds. + Weight::from_parts(50_679_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3522` + // Minimum execution time: 11_707_000 picoseconds. + Weight::from_parts(12_046_000, 3522) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3522` + // Minimum execution time: 10_420_000 picoseconds. + Weight::from_parts(10_842_000, 3522) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_utility.rs b/tracing/3100/runtime/common/src/weights/pallet_utility.rs new file mode 100644 index 00000000..48f082f3 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_utility.rs @@ -0,0 +1,105 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_utility` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_utility +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_utility`. +pub struct WeightInfo(PhantomData); +impl pallet_utility::WeightInfo for WeightInfo { + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 3_953_000 picoseconds. + Weight::from_parts(3_035_286, 1527) + // Standard Error: 3_178 + .saturating_add(Weight::from_parts(4_128_538, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn as_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 6_437_000 picoseconds. + Weight::from_parts(6_878_000, 1527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn batch_all(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_049_000 picoseconds. + Weight::from_parts(10_287_583, 1527) + // Standard Error: 3_445 + .saturating_add(Weight::from_parts(4_320_181, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_152_000 picoseconds. + Weight::from_parts(6_423_000, 0) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn force_batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_017_000 picoseconds. + Weight::from_parts(7_530_202, 1527) + // Standard Error: 3_607 + .saturating_add(Weight::from_parts(4_126_047, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_whitelist.rs b/tracing/3100/runtime/common/src/weights/pallet_whitelist.rs new file mode 100644 index 00000000..62dbcc92 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_whitelist.rs @@ -0,0 +1,118 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_whitelist` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_whitelist +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_whitelist`. +pub struct WeightInfo(PhantomData); +impl pallet_whitelist::WeightInfo for WeightInfo { + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn whitelist_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `46` + // Estimated: `3544` + // Minimum execution time: 16_105_000 picoseconds. + Weight::from_parts(16_696_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn remove_whitelisted_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `3544` + // Minimum execution time: 16_313_000 picoseconds. + Weight::from_parts(16_748_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 4194294]`. + fn dispatch_whitelisted_call(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `251 + n * (1 ±0)` + // Estimated: `3715 + n * (1 ±0)` + // Minimum execution time: 26_740_000 picoseconds. + Weight::from_parts(27_172_000, 3715) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 10000]`. + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `3544` + // Minimum execution time: 19_842_000 picoseconds. + Weight::from_parts(20_402_977, 3544) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_385, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_xcm.rs b/tracing/3100/runtime/common/src/weights/pallet_xcm.rs new file mode 100644 index 00000000..ff9b67c6 --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_xcm.rs @@ -0,0 +1,336 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_xcm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_xcm`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 18_925_000 picoseconds. + Weight::from_parts(19_358_000, 3610) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn reserve_transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `519` + // Estimated: `3984` + // Minimum execution time: 89_261_000 picoseconds. + Weight::from_parts(90_775_000, 3984) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `3682` + // Minimum execution time: 79_931_000 picoseconds. + Weight::from_parts(81_869_000, 3682) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + fn execute() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_758_000 picoseconds. + Weight::from_parts(10_156_000, 0) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_428_000 picoseconds. + Weight::from_parts(6_620_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_default_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_879_000 picoseconds. + Weight::from_parts(2_026_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_subscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 24_293_000 picoseconds. + Weight::from_parts(24_859_000, 3610) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_unsubscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `328` + // Estimated: `3793` + // Minimum execution time: 25_970_000 picoseconds. + Weight::from_parts(26_461_000, 3793) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_814_000 picoseconds. + Weight::from_parts(1_968_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_supported_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `125` + // Estimated: `13490` + // Minimum execution time: 25_617_000 picoseconds. + Weight::from_parts(26_234_000, 13490) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notifiers() -> Weight { + // Proof Size summary in bytes: + // Measured: `129` + // Estimated: `13494` + // Minimum execution time: 26_192_000 picoseconds. + Weight::from_parts(26_555_000, 13494) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn already_notified_target() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `15982` + // Minimum execution time: 32_031_000 picoseconds. + Weight::from_parts(32_664_000, 15982) + .saturating_add(T::DbWeight::get().reads(6_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_current_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 26_344_000 picoseconds. + Weight::from_parts(26_968_000, 6152) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn notify_target_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `172` + // Estimated: `11062` + // Minimum execution time: 19_243_000 picoseconds. + Weight::from_parts(19_787_000, 11062) + .saturating_add(T::DbWeight::get().reads(4_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notify_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `13501` + // Minimum execution time: 26_389_000 picoseconds. + Weight::from_parts(27_073_000, 13501) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn migrate_and_notify_old_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `13577` + // Minimum execution time: 41_341_000 picoseconds. + Weight::from_parts(41_860_000, 13577) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `1554` + // Minimum execution time: 4_367_000 picoseconds. + Weight::from_parts(4_535_000, 1554) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7706` + // Estimated: `11171` + // Minimum execution time: 24_798_000 picoseconds. + Weight::from_parts(25_546_000, 11171) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `126` + // Estimated: `3591` + // Minimum execution time: 39_745_000 picoseconds. + Weight::from_parts(40_916_000, 3591) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3100/runtime/common/src/weights/pallet_xcm_transactor.rs b/tracing/3100/runtime/common/src/weights/pallet_xcm_transactor.rs new file mode 100644 index 00000000..00388c8e --- /dev/null +++ b/tracing/3100/runtime/common/src/weights/pallet_xcm_transactor.rs @@ -0,0 +1,204 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_xcm_transactor` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm_transactor +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![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_xcm_transactor`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_transactor::WeightInfo for WeightInfo { + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `3579` + // Minimum execution time: 9_198_000 picoseconds. + Weight::from_parts(9_554_000, 3579) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::IndexToAccount` (r:0 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_363_000 picoseconds. + Weight::from_parts(5_508_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_539_000 picoseconds. + Weight::from_parts(6_747_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_909_000 picoseconds. + Weight::from_parts(6_109_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:0 w:1) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_fee_per_second() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_108_000 picoseconds. + Weight::from_parts(6_331_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:0) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `493` + // Estimated: `3958` + // Minimum execution time: 34_690_000 picoseconds. + Weight::from_parts(35_572_000, 3958) + .saturating_add(T::DbWeight::get().reads(9_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_sovereign() -> Weight { + // Proof Size summary in bytes: + // Measured: `427` + // Estimated: `3892` + // Minimum execution time: 29_237_000 picoseconds. + Weight::from_parts(30_158_000, 3892) + .saturating_add(T::DbWeight::get().reads(7_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transact_through_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `471` + // Estimated: `3936` + // Minimum execution time: 42_854_000 picoseconds. + Weight::from_parts(43_716_000, 3936) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn hrmp_manage() -> Weight { + // Proof Size summary in bytes: + // Measured: `475` + // Estimated: `3940` + // Minimum execution time: 44_985_000 picoseconds. + Weight::from_parts(46_162_000, 3940) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3100/runtime/moonbase/Cargo.toml b/tracing/3100/runtime/moonbase/Cargo.toml new file mode 100644 index 00000000..4c9670de --- /dev/null +++ b/tracing/3100/runtime/moonbase/Cargo.toml @@ -0,0 +1,430 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonbase Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbase-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } +precompile-foreign-asset-migrator = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-debug-derive = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +pallet-evm-precompile-storage-cleaner = { workspace = true } +precompile-utils = { workspace = true } + + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +pallet-message-queue = { workspace = true } +polkadot-core-primitives = { workspace = true } +polkadot-parachain = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-emergency-para-xcm = { workspace = true } +pallet-evm-precompile-xcm = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-emergency-para-xcm/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-registry/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompileset-assets-erc20/std", + "pallet-evm-precompile-storage-cleaner/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-foreign-assets/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] + +# Must be enabled for tracing runtimes only +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Allow to print logs details (no wasm:stripped) +force-debug = ["sp-debug-derive/force-debug"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-foreign-assets/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] + +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-emergency-para-xcm/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-preimage/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-sudo/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-precompile-benchmarks/try-runtime", +] + +moonbase-runtime-benchmarks = [] diff --git a/tracing/3100/runtime/moonbase/build.rs b/tracing/3100/runtime/moonbase/build.rs new file mode 100644 index 00000000..3934b9c5 --- /dev/null +++ b/tracing/3100/runtime/moonbase/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/tracing/3100/runtime/moonbase/src/asset_config.rs b/tracing/3100/runtime/moonbase/src/asset_config.rs new file mode 100644 index 00000000..8aa9e297 --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/asset_config.rs @@ -0,0 +1,218 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use crate::OpenTechCommitteeInstance; + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, Assets, Balance, Balances, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; + +use frame_system::{EnsureNever, EnsureRoot}; +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::H160; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::UNIT * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonbeam_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + crate::AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} + +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonbeam_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3100/runtime/moonbase/src/governance/councils.rs b/tracing/3100/runtime/moonbase/src/governance/councils.rs new file mode 100644 index 00000000..d6addeae --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/governance/councils.rs @@ -0,0 +1,62 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; +use moonbeam_runtime_common::weights as moonbeam_weights; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * BlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3100/runtime/moonbase/src/governance/mod.rs b/tracing/3100/runtime/moonbase/src/governance/mod.rs new file mode 100644 index 00000000..36a2c6be --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3100/runtime/moonbase/src/governance/origins.rs b/tracing/3100/runtime/moonbase/src/governance/origins.rs new file mode 100644 index 00000000..e8de3c35 --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/governance/origins.rs @@ -0,0 +1,83 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3100/runtime/moonbase/src/governance/referenda.rs b/tracing/3100/runtime/moonbase/src/governance/referenda.rs new file mode 100644 index 00000000..96bb3628 --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/governance/referenda.rs @@ -0,0 +1,101 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::*; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use moonbeam_runtime_common::weights as moonbeam_weights; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * UNIT * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; + +/// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3100/runtime/moonbase/src/governance/tracks.rs b/tracing/3100/runtime/moonbase/src/governance/tracks.rs new file mode 100644 index 00000000..72e18b9f --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{KILOUNIT, SUPPLY_FACTOR, UNIT}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 100 * KILOUNIT * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 500 * UNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(50)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 20 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 500 * UNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3100/runtime/moonbase/src/lib.rs b/tracing/3100/runtime/moonbase/src/lib.rs new file mode 100644 index 00000000..10625718 --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/lib.rs @@ -0,0 +1,1840 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonbase Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonbase tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "512"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod asset_config; +pub mod governance; +pub mod xcm_config; + +mod migrations; +mod precompiles; + +// Re-export required by get! macro. +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +pub use pallet_author_slot_filter::EligibilityValue; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +pub use precompiles::{ + MoonbasePrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +use fp_rpc::TransactionStatus; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, FindAuthor, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, + PalletId, +}; + +use frame_system::{EnsureRoot, EnsureSigned}; +use governance::councils::*; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonbeam_weights, +}; +use nimbus_primitives::CanAuthor; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, +}; +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; +use xcm::{ + v3::{AssetId as XcmAssetId, Location}, + IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_config::AssetType; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; +use xcm_primitives::UnitsToWeightRatio; + +use smallvec::smallvec; +use sp_runtime::serde::{Deserialize, Serialize}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonbasePrecompiles; + +/// UNIT, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 1; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROUNIT: Balance = 1_000_000_000_000; + pub const MILLIUNIT: Balance = 1_000_000_000_000_000; + pub const UNIT: Balance = 1_000_000_000_000_000_000; + pub const KILOUNIT: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * UNIT * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(2) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonbase"), + impl_name: create_runtime_str!("moonbase"), + authoring_version: 4, + spec_version: 3100, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 2, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// TODO: this is left here so that `impl_runtime_apis_plus_common` will find the same type for + /// `BlockWeights` in all runtimes. It can probably be removed once the custom + /// `RuntimeBlockWeights` has been pushed to each runtime. + pub BlockWeights: frame_system::limits::BlockWeights = RuntimeBlockWeights::get(); + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1287>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonbeam_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonbeam_weights::pallet_timestamp::WeightInfo; +} + +#[cfg(not(feature = "runtime-benchmarks"))] +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonbeam_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% are burned, 20% to the treasury + let (_, to_treasury) = fees.ration(80, 20); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = FastAdjustingFeeUpdate; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonbeam_weights::pallet_sudo::WeightInfo; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2 sec Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; +/// The highest amount of new storage that can be created in a block (160KB). +pub const BLOCK_STORAGE_LIMIT: u64 = 160 * 1024; +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This fast multiplier responds by doubling/halving in + /// approximately one hour at extreme block congestion levels. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonbasePrecompiles = MoonbasePrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 16 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 16; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// (60_000_000 / 160 kb) + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // TODO: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// A "Fast" TargetedFeeAdjustment. Parameters chosen based on model described here: +/// https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#-1.-fast-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type FastAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +/// The author inherent provides an AccountId, but pallet evm needs an H160. +/// This simple adapter makes the conversion for any types T, U such that T: Into +pub struct FindAuthorAdapter(sp_std::marker::PhantomData<(T, U, Inner)>); + +impl FindAuthor for FindAuthorAdapter +where + T: Into, + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonbasePrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonbeam_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; + pub const NoPreimagePostponement: Option = Some(10); +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonbeam_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::UNIT * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonbeam_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonbeam_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = EmergencyParaXcm; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = EmergencyParaXcm; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_parachain_system::weights::SubstrateWeight; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} + +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<2>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<2>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<2>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<2>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<2>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<2>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 500 * currency::UNIT * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonbeam_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonbeam_weights::pallet_author_inherent::WeightInfo; +} + +#[cfg(test)] +mod mock { + use super::*; + pub struct MockRandomness; + impl frame_support::traits::Randomness for MockRandomness { + fn random(subject: &[u8]) -> (H256, BlockNumber) { + (H256(sp_io::hashing::blake2_256(subject)), 0) + } + } +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(test))] + type RandomnessSource = Randomness; + #[cfg(test)] + type RandomnessSource = mock::MockRandomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonbeam_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonbase-"; + +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + // TODO to be revisited + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonbeam_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::TreasuryCouncilInstance + | PrecompileName::ReferendaPrecompile + | PrecompileName::ConvictionVotingPrecompile + | PrecompileName::PreimagePrecompile + | PrecompileName::OpenTechCommitteeInstance, + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::IdentityPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonbeam_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // TODO wire up our correct list of migrations here. Maybe this shouldn't be in + // `moonbeam_runtime_common`. + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonbaseMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<3>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonbeam_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonbeam_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonbeam_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_precompile_benchmarks::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + Utility: pallet_utility::{Pallet, Call, Event} = 1, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 3, + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event} = 4, + // Previously 5: pallet_randomness_collective_flip + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 6, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 7, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 8, + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 9, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 10, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 11, + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 12, + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 13, + // Previously 14: pallet_democracy::{Pallet, Storage, Config, Event, Call} = 14, + // Previously 15: CouncilCollective: pallet_collective:: + // Previously 16: TechCommitteeCollective: pallet_collective:: + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 17, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 18, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 19, + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 20, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 21, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 22, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 23, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 24, + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 25, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 26, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 27, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 28, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 29, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 30, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 31, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 32, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Config, Storage, Event} = 33, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 34, + // Previously 35: BaseFee + // Previously 36: pallet_assets:: + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event, Config} = 37, + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 38, + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 39, + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 40, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 41, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 42, + Origins: governance::custom_origins::{Origin} = 43, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 44, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 45, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 46, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 47, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 48, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 49, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 50, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 51, + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 52, + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 53, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 54, + EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 55, + EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 56, + } +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_sudo, Sudo] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_foreign_assets, EvmForeignAssets] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_relay_storage_roots, RelayStorageRoots] + [pallet_precompile_benchmarks, PrecompileBenchmarks] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + ); +} + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to effective priority fee from pallet ethereum. If it is any other kind of + // transaction, we modify its priority. The goal is to arrive at a similar metric used + // by pallet ethereum, which means we derive a fee-per-gas from the txn's tip and + // weight. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + let tip_per_gas = if effective_gas > 0 { + tip.saturating_div(effective_gas as u128) + } else { + 0 + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = tip_per_gas as u64; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 1); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(1 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(100 * MICROUNIT)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(1 * UNIT) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(1 * UNIT + 25800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(100 * MICROUNIT) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(1 * UNIT + 5300 * MICROUNIT) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(500 * UNIT) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(1 * UNIT) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(100 * UNIT) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(1 * UNIT + 800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(2100 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(1 * UNIT + 800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(5600 * MICROUNIT) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn test_proxy_type_can_be_decoded_from_valid_values() { + let test_cases = vec![ + // (input, expected) + (0u8, ProxyType::Any), + (1, ProxyType::NonTransfer), + (2, ProxyType::Governance), + (3, ProxyType::Staking), + (4, ProxyType::CancelProxy), + (5, ProxyType::Balances), + (6, ProxyType::AuthorMapping), + (7, ProxyType::IdentityJudgement), + ]; + + for (input, expected) in test_cases { + let actual = ProxyType::decode(&mut input.to_le_bytes().as_slice()); + assert_eq!( + Ok(expected), + actual, + "failed decoding ProxyType for value '{}'", + input + ); + } + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(BLOCK_STORAGE_LIMIT); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3100/runtime/moonbase/src/migrations.rs b/tracing/3100/runtime/moonbase/src/migrations.rs new file mode 100644 index 00000000..89f5279d --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/migrations.rs @@ -0,0 +1,28 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonbase specific Migrations + +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{prelude::*, vec}; + +pub struct MoonbaseMigrations; + +impl GetMigrations for MoonbaseMigrations { + fn get_migrations() -> Vec> { + vec![] + } +} diff --git a/tracing/3100/runtime/moonbase/src/precompiles.rs b/tracing/3100/runtime/moonbase/src/precompiles.rs new file mode 100644 index 00000000..9d8290f8 --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/precompiles.rs @@ -0,0 +1,352 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, + xcm_config::{AssetType, XcmExecutorConfig}, + OpenTechCommitteeInstance, TreasuryCouncilInstance, +}; +use crate::{AccountId, AssetId, AssetManager, Balances, Erc20XcmBridge, Runtime, H160}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonbase_weights; +use moonkit_xcm_primitives::{ + location_matcher::{Erc20PalletMatcher, ForeignAssetMatcher, SingleAddressMatcher}, + AccountIdAssetIdConversion, +}; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_storage_cleaner::StorageCleanerPrecompile; +use pallet_evm_precompile_xcm::PalletXcmPrecompile; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::{AllExceptXcmExecute, XcmUtilsPrecompile}; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_foreign_asset_migrator::ForeignAssetMigratorPrecompile; +use precompile_utils::precompile_set::*; +use sp_std::prelude::*; +use xcm_primitives::AsAssetType; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonbase_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +/// ERC20 metadata for the native token. +pub struct NativeErc20Metadata; + +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "DEV token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "DEV" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as local +pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8, 255u8, 255u8, 254u8]; + +/// Const to identify ERC20_BALANCES_PRECOMPILE address +pub const ERC20_BALANCES_PRECOMPILE: u64 = 2050; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; + pub LocalAssetPrefix: &'static [u8] = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +// Pallet-xcm precompile types. +// Type that converts AssetId into Location +type AssetIdToLocationManager = AsAssetType; + +// The pallet-balances address is identified by ERC20_BALANCES_PRECOMPILE const +type SingleAddressMatch = SingleAddressMatcher; + +// Type that matches an AccountId with a foreign asset address (if any) +type ForeignAssetMatch = ForeignAssetMatcher; + +// Erc20XcmBridge pallet is used to match ERC20s +type Erc20Match = Erc20PalletMatcher; + +#[precompile_utils::precompile_name_from_address] +type MoonbasePrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + PrecompileAt, StorageCleanerPrecompile, CallableByPrecompile>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // DemocracyPrecompile + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract>, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + // CouncilCollective precompile + RemovedPrecompileAt>, + // TechCommitteeCollective precompile + RemovedPrecompileAt>, + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2074>, + PalletXcmPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, ForeignAssetMigratorPrecompile, ()>, +); + +pub struct DisabledLocalAssets(sp_std::marker::PhantomData); + +impl sp_core::Get> for DisabledLocalAssets +where + Runtime: frame_system::Config, + Runtime::AccountId: Into, + Runtime: AccountIdAssetIdConversion, +{ + fn get() -> Vec { + vec![ + // https://moonbase.subscan.io/extrinsic/5245322-6?event=5245322-22 + 182085191673801920759598290391359780050u128, + // https://moonbase.subscan.io/extrinsic/3244752-4?event=3244752-9 + 282223684955665977914983262584256755878u128, + // https://moonbase.subscan.io/extrinsic/3158280-4?event=3158280-9 + 235962050501460763853961856666389569138u128, + // https://moonbase.subscan.io/block/3045900?tab=event&&event=3045900-4 + 45350527686064227409532032051821627910u128, + // https://moonbase.subscan.io/extrinsic/3024306-4?event=3024306-9 + 199439015574556113723291251263369885338u128, + // https://moonbase.subscan.io/extrinsic/2921640-4?event=2921640-9 + 236426850287284823323011839750645103615u128, + // https://moonbase.subscan.io/extrinsic/2748867-4?event=2748867-9 + 14626673838203901761839010613793775004u128, + // https://moonbase.subscan.io/extrinsic/2709788-4?event=2709788-9 + 95328064580428769161981851380106820590u128, + // https://moonbase.subscan.io/extrinsic/2670844-4?event=2670844-9 + 339028723712074529056817184013808486301u128, + // https://moonbase.subscan.io/extrinsic/2555083-4?event=2555083-9 + 100481493116602214283160747599845770751u128, + // https://moonbase.subscan.io/extrinsic/2473880-3?event=2473880-8 + 319515966007349957795820176952936446433u128, + // https://moonbase.subscan.io/extrinsic/2346438-3?event=2346438-6 + 337110116006454532607322340792629567158u128, + // https://moonbase.subscan.io/extrinsic/2239102-3?event=2239102-6 + 255225902946708983196362678630947296516u128, + // https://moonbase.subscan.io/extrinsic/2142964-4?event=2142964-12 + 3356866138193769031598374869367363824u128, + // https://moonbase.subscan.io/extrinsic/1967538-6?event=1967538-28 + 144992676743556815849525085098140609495u128, + ] + .iter() + .map(|id| Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, *id).into()) + .collect() + } +} + +/// The PrecompileSet installed in the Moonbase runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonbasePrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonbasePrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompilesAt>, + ), +>; diff --git a/tracing/3100/runtime/moonbase/src/xcm_config.rs b/tracing/3100/runtime/moonbase/src/xcm_config.rs new file mode 100644 index 00000000..7b1da02f --- /dev/null +++ b/tracing/3100/runtime/moonbase/src/xcm_config.rs @@ -0,0 +1,809 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, + EmergencyParaXcm, Erc20XcmBridge, EvmForeignAssets, MaintenanceMode, MessageQueue, + ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, + RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue, +}; +use crate::OpenTechCommitteeInstance; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; +use sp_weights::Weight; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; + +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + FirstAssetTrader, IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, + UtilityEncodeCall, XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Westend; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + // The universal location within the global consensus system + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + + + // Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents: 0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +// This is intended to match FOREIGN ASSETS +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +// These correspond to +// SelfReserve asset, both pre and post 0.9.16 +// Foreign assets +// We can remove the Old reanchor once +// we import https://github.com/open-web3-stack/open-runtime-module-library/pull/708 +pub type AssetTransactors = ( + LocalAssetTransactor, + EvmForeignAssets, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +/// We do not burn anything because we want to mimic exactly what +/// the sovereign account has +pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount< + super::Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1001)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + UsingComponents< + ::WeightToFee, + SelfReserve, + AccountId, + Balances, + DealWithFees, + >, + FirstAssetTrader, + ); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // TODO pallet-xcm weights + type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 128 * 1048; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = EmergencyParaXcm; + type WeightInfo = pallet_message_queue::weights::SubstrateWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +impl pallet_emergency_para_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type XcmpMessageHandler = XcmpQueue; + type PausedThreshold = ConstU32<300>; + type FastAuthorizeUpgradeOrigin = + pallet_collective::EnsureProportionAtLeast; + type PausedToNormalOrigin = + pallet_collective::EnsureProportionAtLeast; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We take it +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // A foreign asset + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight + = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; + +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // AssetHub fee + (1, Some(Parachain(1001u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation<( + EvmForeignAssets, + AsAssetType, + )>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 WND/ROC should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation<( + EvmForeignAssets, + AsAssetType, + )>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +pub struct AccountIdToH160; +impl sp_runtime::traits::Convert for AccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + account_id.into() + } +} + +pub struct EvmForeignAssetIdFilter; +impl frame_support::traits::Contains for EvmForeignAssetIdFilter { + fn contains(asset_id: &AssetId) -> bool { + use xcm_primitives::AssetTypeGetter as _; + // We should return true only if the AssetId doesn't exist in AssetManager + AssetManager::get_asset_type(*asset_id).is_none() + } +} + +pub type ForeignAssetManagerOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::FastGeneralAdmin, + >, +>; + +impl pallet_moonbeam_foreign_assets::Config for Runtime { + type AccountIdToH160 = AccountIdToH160; + type AssetIdFilter = EvmForeignAssetIdFilter; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; + type ForeignAssetCreatorOrigin = ForeignAssetManagerOrigin; + type ForeignAssetFreezerOrigin = ForeignAssetManagerOrigin; + type ForeignAssetModifierOrigin = ForeignAssetManagerOrigin; + type ForeignAssetUnfreezerOrigin = ForeignAssetManagerOrigin; + type OnForeignAssetCreated = (); + type MaxForeignAssets = ConstU32<256>; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonbeam_weights::pallet_moonbeam_foreign_assets::WeightInfo; + type XcmLocationToH160 = LocationToH160; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3100/runtime/moonbase/tests/common/mod.rs b/tracing/3100/runtime/moonbase/tests/common/mod.rs new file mode 100644 index 00000000..19df108a --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/common/mod.rs @@ -0,0 +1,405 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonbase_runtime::{ + currency::UNIT, AccountId, AsyncBacking, AuthorInherent, Balance, Ethereum, EvmForeignAssets, + InflationInfo, ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, + TransactionConverter, UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; +use pallet_transaction_payment::Multiplier; + +pub fn existential_deposit() -> u128 { + ::ExistentialDeposit::get() +} + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f86d8205018085174876e80085e8d4a5100082520894f24ff3a9cf04c71dbc94d0b566f7a27b9456\ + 6cac8080c001a0e1094e1a52520a75c0255db96132076dd0f1263089f838bea548cbdbfc64a4d19f031c\ + 92a8cb04e2d68d20a6158d542a07ac440cc8d07b6e36af02db046d92df"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f86180843b9aca00809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ca00e28ba2dd3c5a\ + 3fd467d4afd7aefb4a34b373314fff470bb9db743a84d674a0aa06e5994f2d07eafe1c37b4ce5471ca\ + ecec29011f6f5bf0b1a552c55ea348df35f"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_id: u128, + pub xcm_location: xcm::v4::Location, + pub decimals: u8, + pub name: &'static str, + pub symbol: &'static str, + pub balances: Vec<(AccountId, Balance)>, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccoutId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * UNIT, + ideal: 200_000 * UNIT, + max: 500_000 * UNIT, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 2 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_transaction_payment::GenesisConfig:: { + multiplier: Multiplier::from(8u128), + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + + let xcm_assets = self.xcm_assets.clone(); + + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id = xcm_asset_initialization.asset_id; + EvmForeignAssets::create_foreign_asset( + root_origin(), + asset_id, + xcm_asset_initialization.xcm_location, + xcm_asset_initialization.decimals, + xcm_asset_initialization + .symbol + .as_bytes() + .to_vec() + .try_into() + .expect("too long"), + xcm_asset_initialization + .name + .as_bytes() + .to_vec() + .try_into() + .expect("too long"), + ) + .expect("fail to create foreign asset"); + + for (account, balance) in xcm_asset_initialization.balances { + if EvmForeignAssets::mint_into(asset_id, account, balance.into()).is_err() { + panic!("fail to mint foreign asset"); + } + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3100/runtime/moonbase/tests/evm_tracing.rs b/tracing/3100/runtime/moonbase/tests/evm_tracing.rs new file mode 100644 index 00000000..5a5b06ec --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * UNIT)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3100/runtime/moonbase/tests/integration_test.rs b/tracing/3100/runtime/moonbase/tests/integration_test.rs new file mode 100644 index 00000000..3647d37b --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/integration_test.rs @@ -0,0 +1,3138 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Integration Tests + +mod common; +use common::*; + +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{ + fungible::Inspect, Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, + StorageInfoTrait, + }, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbase_runtime::{ + //asset_config::ForeignAssetInstance, + xcm_config::SelfReserve, + AccountId, + AssetId, + Balances, + CrowdloanRewards, + EvmForeignAssets, + Executive, + OpenTechCommitteeCollective, + ParachainStaking, + PolkadotXcm, + Precompiles, + Runtime, + RuntimeBlockWeights, + RuntimeCall, + RuntimeEvent, + System, + TransactionPayment, + TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, + XTokens, + XcmTransactor, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::testing::MockHandle; +use sp_runtime::{ + traits::{Convert as XcmConvert, Dispatchable}, + BuildStorage, +}; +use std::str::from_utf8; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +use moonbase_runtime::currency::{GIGAWEI, WEI}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +//use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_moonbeam_foreign_assets::AssetStatus; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, HrmpOperation, TransactWeights}; +use parity_scale_codec::Encode; +use sha3::{Digest, Keccak256}; +use sp_core::{crypto::UncheckedFrom, ByteArray, Pair, H160, H256, U256}; +use sp_runtime::{bounded_vec, DispatchError, ModuleError}; +use std::cell::Cell; +use std::rc::Rc; +use xcm::latest::prelude::*; + +type AuthorMappingPCall = + pallet_evm_precompile_author_mapping::AuthorMappingPrecompileCall; +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonbase_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +/*type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>;*/ +type XcmTransactorV1PCall = + pallet_evm_precompile_xcm_transactor::v1::XcmTransactorPrecompileV1Call; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +// TODO: can we construct a const U256...? +const BASE_FEE_GENISIS: u128 = 10 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait from https://github.com/paritytech/substrate/pull/9246 + // This is now available with polkadot-v0.9.9 dependencies + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("EthereumXcm"); + is_pallet_prefix::("Randomness"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"Sudo".to_vec(), + storage_name: b"Key".to_vec(), + prefix: prefix(b"Sudo", b"Key"), + max_values: Some(1), + max_size: Some(20), + }] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonbase_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + is_pallet_index::(6); + is_pallet_index::(7); + is_pallet_index::(8); + is_pallet_index::(9); + is_pallet_index::(10); + is_pallet_index::(11); + is_pallet_index::(12); + is_pallet_index::(13); + //is_pallet_index::(14); Removed + is_pallet_index::(17); + is_pallet_index::(18); + is_pallet_index::(19); + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + is_pallet_index::(25); + is_pallet_index::(26); + is_pallet_index::(27); + is_pallet_index::(28); + is_pallet_index::(29); + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(37); + is_pallet_index::(38); + is_pallet_index::(39); + is_pallet_index::(40); + is_pallet_index::(46); + is_pallet_index::(51); +} + +#[test] +fn verify_reserved_indices() { + use frame_metadata::*; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + let metadata = moonbase_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 35: BaseFee + // 36: pallet_assets:: + let reserved = vec![35, 36]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonbase_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonbase_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonbase_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonbase_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonbase_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonbase_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonbase_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonbase_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 2_000 * UNIT), + (AccountId::from(CHARLIE), 1_100 * UNIT), + (AccountId::from(DAVE), 1_000 * UNIT), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 1_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![ + (AccountId::from(CHARLIE), AccountId::from(ALICE), 50 * UNIT), + (AccountId::from(CHARLIE), AccountId::from(BOB), 50 * UNIT), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 1_000 * UNIT, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 1_000 * UNIT, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 1_000 * UNIT, + new_total_amt_locked: 3_100 * UNIT + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 1_050 * UNIT); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 1_050 * UNIT); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 1_000 * UNIT); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 0u32 + ), + DispatchError::Module(ModuleError { + index: 12, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + + // Alice transfer from free balance 2000 UNIT to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 2_000 * UNIT, + )); + assert_eq!(Balances::free_balance(AccountId::from(BOB)), 2_000 * UNIT); + + let gas_limit = 100000u64; + // Bob transfers 1000 UNIT to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: Vec::new(), + value: (1_000 * UNIT).into(), + gas_limit, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 1_000 * UNIT, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 0u32, + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 1_000 * UNIT); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 2_100 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + // Just before round 3 + run_to_block(2399, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1_100 * UNIT, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,); + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1213666666584000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 541333333292000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 2_100 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + (AccountId::from(CHARLIE), UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 2 + run_to_block(1199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1_100 * UNIT, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,); + assert_eq!(Balances::usable_balance(AccountId::from(CHARLIE)), UNIT,); + + // Go to round 2 + run_to_block(1201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 47515000000000000000, + ); + + // Go to round 3 + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1182693333281650000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 525841666640825000000, + ); + // 30% again reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 94727725000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * UNIT); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * UNIT); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![([4u8; 32].into(), Some(AccountId::from(ALICE)), 432000)] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * UNIT) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (450_000 * UNIT) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (450_000 * UNIT) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature: + // WRAP_BYTES|| NetworkIdentifier|| new_account || previous_account || WRAP_BYTES + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonbase-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * UNIT); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * UNIT) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * UNIT); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * UNIT); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENISIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * UNIT) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(BOB.into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(CHARLIE.into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * UNIT).into(); + let expected_claimed: U256 = (450_000 * UNIT).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENISIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + ); + }) +} + +#[test] +fn create_and_manipulate_foreign_asset() { + ExtBuilder::default().build().execute_with(|| { + let source_location = xcm::v4::Location::parent(); + + // Create foreign asset + assert_ok!(EvmForeignAssets::create_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + source_location.clone(), + 12, + bounded_vec![b'M', b'T'], + bounded_vec![b'M', b'y', b'T', b'o', b'k'], + )); + assert_eq!( + EvmForeignAssets::assets_by_id(1), + Some(source_location.clone()) + ); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::Active)) + ); + + // Freeze foreign asset + assert_ok!(EvmForeignAssets::freeze_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + true + )); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::FrozenXcmDepositAllowed)) + ); + + // Unfreeze foreign asset + assert_ok!(EvmForeignAssets::unfreeze_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + )); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::Active)) + ); + }); +} + +// The precoompile asset-erc20 is deprecated and not used anymore for new evm foreign assets +// We don't have testing tools in rust test to call real evm smart contract, so we rely on ts tests. +/* +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!(Assets::total_supply(relay_asset_id), 1_000 * UNIT); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * UNIT)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * UNIT)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Alice to Bob, 400 UNIT. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(24342) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Make sure BOB has 400 UNIT + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * UNIT)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 UNIT from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(14424) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(29686) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 UNIT + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * UNIT)); + }); +}*/ + +#[test] +fn xtokens_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = 1; + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + let inside = Rc::new(Cell::new(false)); + let inside2 = inside.clone(); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(209239) + .expect_no_logs() + // We expect an evm subcall ERC20.burnFrom + .with_subcall_handle(move |subcall| { + let Subcall { + address, + transfer, + input, + target_gas: _, + is_static, + context, + } = subcall; + + assert_eq!(context.caller, EvmForeignAssets::account_id().into()); + assert_eq!( + address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(is_static, false); + + assert!(transfer.is_none()); + + assert_eq!( + context.address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(context.apparent_value, 0u8.into()); + + assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]); + assert_eq!(&input[4..16], &[0u8; 12]); + assert_eq!(&input[16..36], ALICE); + + inside2.set(true); + + SubcallOutput { + output: Default::default(), + cost: 149_000, + logs: vec![], + ..SubcallOutput::succeed() + } + }) + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompiles_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + let inside = Rc::new(Cell::new(false)); + let inside2 = inside.clone(); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(209239) + .expect_no_logs() + // We expect an evm subcall ERC20.burnFrom + .with_subcall_handle(move |subcall| { + let Subcall { + address, + transfer, + input, + target_gas: _, + is_static, + context, + } = subcall; + + assert_eq!(context.caller, EvmForeignAssets::account_id().into()); + assert_eq!( + address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(is_static, false); + + assert!(transfer.is_none()); + + assert_eq!( + context.address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(context.apparent_value, 0u8.into()); + + assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]); + assert_eq!(&input[4..16], &[0u8; 12]); + assert_eq!(&input[16..36], ALICE); + + inside2.set(true); + + SubcallOutput { + output: Default::default(), + cost: 149_000, + logs: vec![], + ..SubcallOutput::succeed() + } + }) + .execute_returns(()); + + // Ensure that the subcall was actually called. + assert!(inside.get(), "subcall not called"); + }) +} + +#[test] +fn xtokens_precompiles_transfer_native() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Its address is + let asset_precompile_address = H160::from_low_u64_be(2050); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address), + amount: { 500 * UNIT }.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(16000) + .expect_no_logs() + .execute_returns(()); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonbase_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 1_000_000_001, calc_fee(1)); + assert_eq!( 10_000_001_000, calc_fee(10)); + assert_eq!( 100_001_000_000, calc_fee(100)); + assert_eq!( 1_001_000_000_000, calc_fee(1_000)); + assert_eq!( 11_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 1_100_000_000_000_000, calc_fee(100_000)); + assert_eq!( 1_001_000_000_000_000_000, calc_fee(1_000_000)); // one UNIT, ~ 1MB + assert_eq!( 1_000_010_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonbase_runtime::MinimumMultiplier::get(); + let target = moonbase_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = moonbase_runtime::FastAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * UNIT) + (1 * WEI)), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * UNIT, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(8u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 10_000_000_000u128.into(), + Weight::from_parts(25_000_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * UNIT) + (21_000 * BASE_FEE_GENISIS)) + (1 * WEI), + ), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * UNIT) + (21_777 * BASE_FEE_GENISIS) + existential_deposit()), + ), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_777u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENISIS + existential_deposit(), + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * UNIT); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * UNIT,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS) + existential_deposit()), + ), + (AccountId::from(ALICE), existential_deposit()), + ( + as sp_core::TypedGet>::get(), + existential_deposit(), + ), + ]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(2 * BASE_FEE_GENISIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENISIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 1 * base_fee + tip. + let fee = ((2 * BASE_FEE_GENISIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbase_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + use fp_evm::FeeCalculator; + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS)), + ), + (AccountId::from(ALICE), existential_deposit()), + ( + as sp_core::TypedGet>::get(), + existential_deposit(), + ), + ]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 1 GWEI base fee. + let base_fee = TransactionPaymentAsGasPrice::min_gas_price().0; + assert_eq!(base_fee.as_u128(), BASE_FEE_GENISIS); // hint in case following asserts fail + let fee = (base_fee.as_u128() * 21_000u128) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbase_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + }]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbase_runtime::AssetId = 1; + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Unlimited + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(4) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Unlimited + )); + }) +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + }]) + .build() + .execute_with(|| { + let source_id: moonbase_runtime::AssetId = 1; + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId( + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id) + ), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn root_can_use_hrmp_manage() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // It fails sending, because the router does not work in test mode + // But all rest checks pass + assert_noop!( + XcmTransactor::hrmp_manage( + root_origin(), + HrmpOperation::Accept { + para_id: 2000u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(10000) + }, + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: Some(Limited(20000.into())) + } + ), + pallet_xcm_transactor::Error::::ErrorValidating + ); + }) +} + +#[test] +fn transact_through_signed_precompile_works_v1() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let xcm_transactor_v1_precompile_address = H160::from_low_u64_be(2054); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + Weight::from_parts(200_000, (xcm_primitives::DEFAULT_PROOF_SIZE) + 4000), + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v1_precompile_address, + XcmTransactorV1PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 15000, + call: bytes.into(), + }, + ) + .expect_cost(18748) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(18748) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +// Test to ensure we can use either in crowdloan rewards without worrying for migrations +#[test] +fn account_id_32_encodes_like_32_byte_u8_slice() { + let account_as_account_id_32: sp_runtime::AccountId32 = [1u8; 32].into(); + let account_as_slice = [1u8; 32]; + assert_eq!(account_as_account_id_32.encode(), account_as_slice.encode()); +} + +#[test] +fn author_mapping_precompile_associate_update_and_clear() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let author_mapping_precompile_address = H160::from_low_u64_be(2055); + let first_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let first_vrf_id: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let second_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + let second_vrf_id: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + + // Associate it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::add_association { + nimbus_id: [1u8; 32].into(), + }, + ) + .expect_cost(15119) + .expect_no_logs() + .execute_returns(()); + + let expected_associate_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered { + nimbus_id: first_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + keys: first_vrf_id.clone(), + }); + assert_eq!(last_event(), expected_associate_event); + + // Update it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::update_association { + old_nimbus_id: [1u8; 32].into(), + new_nimbus_id: [2u8; 32].into(), + }, + ) + .expect_cost(14723) + .expect_no_logs() + .execute_returns(()); + + let expected_update_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated { + new_nimbus_id: second_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + new_keys: second_vrf_id.clone(), + }); + assert_eq!(last_event(), expected_update_event); + + // Clear it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::clear_association { + nimbus_id: [2u8; 32].into(), + }, + ) + .expect_cost(15158) + .expect_no_logs() + .execute_returns(()); + + let expected_clear_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRemoved { + nimbus_id: second_nimbus_id, + account_id: AccountId::from(ALICE), + keys: second_vrf_id, + }); + assert_eq!(last_event(), expected_clear_event); + }); +} + +#[test] +fn author_mapping_register_and_set_keys() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let author_mapping_precompile_address = H160::from_low_u64_be(2055); + let first_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let first_vrf_key: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([3u8; 32]).into(); + let second_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + let second_vrf_key: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([4u8; 32]).into(); + + // Associate it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::set_keys { + keys: solidity::encode_arguments(( + H256::from([1u8; 32]), + H256::from([3u8; 32]), + )) + .into(), + }, + ) + .expect_cost(16233) + .expect_no_logs() + .execute_returns(()); + + let expected_associate_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered { + nimbus_id: first_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + keys: first_vrf_key.clone(), + }); + assert_eq!(last_event(), expected_associate_event); + + // Update it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::set_keys { + keys: solidity::encode_arguments(( + H256::from([2u8; 32]), + H256::from([4u8; 32]), + )) + .into(), + }, + ) + .expect_cost(16233) + .expect_no_logs() + .execute_returns(()); + + let expected_update_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated { + new_nimbus_id: second_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + new_keys: second_vrf_key.clone(), + }); + assert_eq!(last_event(), expected_update_event); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_multilocation = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_multilocation, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_multilocation, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_multilocation = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_multilocation) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_multilocation, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonbase_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 1027, 2048, 2049, 2050, 2051, 2052, + 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, + 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() { + use frame_support::dispatch::{DispatchInfo, Pays}; + use moonbase_runtime::{currency, EXTRINSIC_BASE_WEIGHT}; + + ExtBuilder::default().build().execute_with(|| { + let size_bytes = 0; + let tip = 0; + let dispatch_info = DispatchInfo { + weight: Weight::zero(), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; + + assert_eq!( + TransactionPayment::compute_fee(size_bytes, &dispatch_info, tip), + EXTRINSIC_BASE_WEIGHT.ref_time() as u128 * currency::WEIGHT_FEE, + ); + }); +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonbase_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * UNIT), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * UNIT)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[test] +fn validate_transaction_fails_on_filtered_call() { + use sp_runtime::transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidityError, + }; + use sp_transaction_pool::runtime_api::runtime_decl_for_tagged_transaction_queue::TaggedTransactionQueueV3; // editorconfig-checker-disable-line + + ExtBuilder::default().build().execute_with(|| { + let xt = UncheckedExtrinsic::new_unsigned( + pallet_evm::Call::::call { + source: Default::default(), + target: H160::default(), + input: Vec::new(), + value: Default::default(), + gas_limit: Default::default(), + max_fee_per_gas: Default::default(), + max_priority_fee_per_gas: Default::default(), + nonce: Default::default(), + access_list: Default::default(), + } + .into(), + ); + + assert_eq!( + Runtime::validate_transaction(TransactionSource::External, xt, Default::default(),), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonbase_runtime::{ + currency, BlockWeights, FastAdjustingFeeUpdate, LengthToFee, MinimumMultiplier, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = FastAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = 5_000u64; + let tip = 42u128; + type WeightToFeeImpl = + ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = + WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee( + &Weight::from_parts(extrinsic_weight, 1), + )) + LengthToFeeImpl::weight_to_fee(&Weight::from_parts(extrinsic_len as u64, 1)) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: Weight::from_parts(extrinsic_weight, 1), + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(998_600_980), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(999_600_080), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(1_000_600_180), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(1_002_603_380), + ); + + // 1 "real" hour (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(431_710_642), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(786_627_866), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_433_329_383u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(4_758_812_897u128), + ); + + // 1 "real" day (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(125_000_000), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(125_000_000), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(5_653_326_895_069u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(125_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3100/runtime/moonbase/tests/runtime_apis.rs b/tracing/3100/runtime/moonbase/tests/runtime_apis.rs new file mode 100644 index 00000000..7cfb9dc1 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/runtime_apis.rs @@ -0,0 +1,397 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::GenesisAccount; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping, FeeCalculator}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbase_runtime::{Executive, TransactionPaymentAsGasPrice}; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(ALICE), + 2_000 * UNIT + existential_deposit(), + )]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * UNIT), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 2_000 * UNIT), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * UNIT), + (AccountId::from(BOB), 10_000_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} + +// Some Priority-related test ideas +// 1. Eth balance transfer with various gas prices. Priority == gas price +// 2. Eth contract call with various gas prices. Priority == gas price +// 3. System remark with no tip -> calculate expected priority from gas weight mapping +// 4. System remark with tip. +// 5. Operational dispatch has higher priority than normal for otherwise same transactions diff --git a/tracing/3100/runtime/moonbase/tests/xcm_mock/mod.rs b/tracing/3100/runtime/moonbase/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..f556bc47 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/xcm_mock/mod.rs @@ -0,0 +1,272 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +pub mod parachain; +pub mod relay_chain; +pub mod statemint_like; +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; + +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemint { + Runtime = statemint_like::Runtime, + XcmpMessageHandler = statemint_like::MsgQueue, + DmpMessageHandler = statemint_like::MsgQueue, + new_ext = statemint_ext(4), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 4]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (4, Statemint), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { + use statemint_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemintBalances = pallet_balances::Pallet; +pub type StatemintChainPalletXcm = pallet_xcm::Pallet; +pub type StatemintAssets = pallet_assets::Pallet; + +pub type ParachainPalletXcm = pallet_xcm::Pallet; +pub type Assets = pallet_assets::Pallet; + +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; diff --git a/tracing/3100/runtime/moonbase/tests/xcm_mock/parachain.rs b/tracing/3100/runtime/moonbase/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..4f394685 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/xcm_mock/parachain.rs @@ -0,0 +1,1114 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; + +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + AssetId as XcmAssetId, Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, + FixedWeightBounds, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, + NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +pub use moonbase_runtime::xcm_config::AssetType; +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 10; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // The rest of multilocations convert via hashing it + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// These will be our transactors +// We use both transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); + +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +pub type XcmFeesToAccount_ = xcm_primitives::XcmFeesToAccount< + Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +parameter_types! { + // We cannot skip the native trader for some specific tests, so we will have to work with + // a native trader that charges same number of units as weight + // We use both the old and new anchoring logics + pub ParaTokensPerSecond: (XcmAssetId, u128, u128) = ( + AssetId(SelfReserve::get()), + 1000000000000, + 0, + ); +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + + // New Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + // We use three traders + // When we receive either representation of the self-reserve asset, + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + FixedRateOfFungible, + xcm_primitives::FirstAssetTrader, + ); + + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(4u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 ROC/WND should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 40 KB. +const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3100/runtime/moonbase/tests/xcm_mock/relay_chain.rs b/tracing/3100/runtime/moonbase/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..15bb49b9 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(4).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3100/runtime/moonbase/tests/xcm_mock/statemint_like.rs b/tracing/3100/runtime/moonbase/tests/xcm_mock/statemint_like.rs new file mode 100644 index 00000000..48a358c0 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/xcm_mock/statemint_like.rs @@ -0,0 +1,582 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, Everything, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; + +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemint_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemint_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemint_prefix, + + } +); diff --git a/tracing/3100/runtime/moonbase/tests/xcm_tests.rs b/tracing/3100/runtime/moonbase/tests/xcm_tests.rs new file mode 100644 index 00000000..24ad7224 --- /dev/null +++ b/tracing/3100/runtime/moonbase/tests/xcm_tests.rs @@ -0,0 +1,3984 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Xcm Tests + +mod xcm_mock; +use frame_support::{ + assert_ok, + traits::{ConstU32, PalletInfo, PalletInfoAccess}, + weights::constants::WEIGHT_REF_TIME_PER_SECOND, + weights::Weight, + BoundedVec, +}; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use sp_runtime::traits::MaybeEquivalence; +use sp_std::boxed::Box; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, All, BuyExecution, ClearOrigin, DepositAsset, GeneralIndex, + Junction, Junctions, Limited, Location, OriginKind, PalletInstance, Parachain, QueryResponse, + Reanchorable, Response, WeightLimit, WithdrawAsset, Xcm, +}; +use xcm::{VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::*; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; +use xcm_simulator::TestExt; +mod common; +use cumulus_primitives_core::relay_chain::HrmpChannelId; +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // Free execution + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + // Free execution,x full amount received + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // First send relay chain asset to Parachain A like in previous test + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // this represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Native token is substracted in paraA + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // Para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A asset has been credited + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 12500000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because trully the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let response = Response::Version(2); + let querier: Location = [].into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_para_b() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + let response = Response::Version(2); + let querier: Location = [].into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + + ParaA::execute_with(|| { + // advertised version + parachain::XcmVersioner::set_version(2); + }); + + ParaB::execute_with(|| { + // Let's try with v0 + parachain::XcmVersioner::set_version(0); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + ParaA::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(ParachainPalletXcm::force_default_xcm_version( + parachain::RuntimeOrigin::root(), + Some(2) + )); + // Wrap version, which sets VersionedStorage + assert_ok!(::wrap_version( + &Location::new(1, [Parachain(2)]).into(), + mock_message + )); + + parachain::para_roll_to(2); + + // queries should have been updated + assert!(ParachainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 0, + } + .into(); + + ParaA::execute_with(|| { + // Assert that the events vector contains the version change + assert!(parachain::para_events().contains(&expected_supported_version)); + }); + + // Let's ensure talking in v0 works + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + } + .into(); + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaB::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in para A + let expected_supported_version_2: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 2, + } + .into(); + + // Para A should have received the version change + ParaA::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(parachain::para_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced the data of the smart contract is not + // removed, it will have to be updated in a future release when there is the ability to + // remove contract data + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced the data of the smart contract is not + // removed, it will have to be updated in a future release when there is the ability to + // remove contract data + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemint_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemint_asset_a_balances = Location::new( + 1, + [ + Parachain(4), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemintToken".to_vec(), + symbol: b"StatemintToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send asset with previous prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] +fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [Parachain(4u32), PalletInstance(5u8), GeneralIndex(10u128)], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + relay_location, + 0u128, + 0 + )); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + statemint_location_asset, + 0u128, + 1 + )); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemint tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemint USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemint: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemint) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemint_beneficiary = Location { + parents: 1, + interior: [ + Parachain(4), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemint::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemint using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemint_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that BOB received 100 USDC on statemint + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3100/runtime/moonbeam/Cargo.toml b/tracing/3100/runtime/moonbeam/Cargo.toml new file mode 100644 index 00000000..50166b03 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/Cargo.toml @@ -0,0 +1,408 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonbeam Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbeam-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +precompile-utils = { workspace = true } + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +pallet-message-queue = { workspace = true } +polkadot-core-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +polkadot-parachain = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonbeam-xcm-benchmarks/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-relay-encoder/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompileset-assets-erc20/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] + +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-precompile-benchmarks/try-runtime", + "pallet-preimage/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", +] diff --git a/tracing/3100/runtime/moonbeam/build.rs b/tracing/3100/runtime/moonbeam/build.rs new file mode 100644 index 00000000..3934b9c5 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/tracing/3100/runtime/moonbeam/src/asset_config.rs b/tracing/3100/runtime/moonbeam/src/asset_config.rs new file mode 100644 index 00000000..200841c5 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/asset_config.rs @@ -0,0 +1,216 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, AssetManager, Assets, Balance, Balances, + OpenTechCommitteeInstance, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_system::{EnsureNever, EnsureRoot}; +use sp_core::H160; + +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::GLMR * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonbeam_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonbeam_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3100/runtime/moonbeam/src/governance/councils.rs b/tracing/3100/runtime/moonbeam/src/governance/councils.rs new file mode 100644 index 00000000..c8cc1ca3 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/governance/councils.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3100/runtime/moonbeam/src/governance/mod.rs b/tracing/3100/runtime/moonbeam/src/governance/mod.rs new file mode 100644 index 00000000..bfe3def3 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3100/runtime/moonbeam/src/governance/origins.rs b/tracing/3100/runtime/moonbeam/src/governance/origins.rs new file mode 100644 index 00000000..48154cd1 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/governance/origins.rs @@ -0,0 +1,85 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +#![cfg_attr(not(feature = "std"), no_std)] + +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3100/runtime/moonbeam/src/governance/referenda.rs b/tracing/3100/runtime/moonbeam/src/governance/referenda.rs new file mode 100644 index 00000000..62720a0d --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/governance/referenda.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::{GLMR, SUPPLY_FACTOR}; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * GLMR * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +// Origin for general admin or root +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; +// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3100/runtime/moonbeam/src/governance/tracks.rs b/tracing/3100/runtime/moonbeam/src/governance/tracks.rs new file mode 100644 index 00000000..a69cd645 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{GLMR, KILOGLMR, SUPPLY_FACTOR}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 20 * KILOGLMR * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 2 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 100 * GLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 2 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 4 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 100 * GLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3100/runtime/moonbeam/src/lib.rs b/tracing/3100/runtime/moonbeam/src/lib.rs new file mode 100644 index 00000000..1de6ee70 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/lib.rs @@ -0,0 +1,1841 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonbeam Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonbeam tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use fp_rpc::TransactionStatus; + +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonbeam_weights, +}; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use smallvec::smallvec; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, SaturatedConversion, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{ + v3::{AssetId as XcmAssetId, Location}, + IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_config::AssetType; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; +use xcm_primitives::UnitsToWeightRatio; + +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use nimbus_primitives::CanAuthor; + +mod migrations; +mod precompiles; +pub use precompiles::{ + MoonbeamPrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonbeamPrecompiles; + +pub mod asset_config; +pub mod governance; +pub mod xcm_config; +use governance::councils::*; + +/// GLMR, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 100; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROGLMR: Balance = 1_000_000_000_000; + pub const MILLIGLMR: Balance = 1_000_000_000_000_000; + pub const GLMR: Balance = 1_000_000_000_000_000_000; + pub const KILOGLMR: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROGLMR * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 100 * MILLIGLMR * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(1) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +pub const MONTHS: BlockNumber = DAYS * 30; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core datastructures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonbeam"), + impl_name: create_runtime_str!("moonbeam"), + authoring_version: 3, + spec_version: 3100, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 2, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1284>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonbeam_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonbeam_weights::pallet_timestamp::WeightInfo; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonbeam_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% are burned, 20% to the treasury + let (_, to_treasury) = fees.ration(80, 20); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 1000ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 1 * 0.75 ~= 30_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; + +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This low value causes changes to occur slowly over time. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + /// This value is currently only used by pallet-transaction-payment as an assertion that the + /// next multiplier is always > min value. + pub MinimumMultiplier: Multiplier = Multiplier::from(1u128); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonbeamPrecompiles = MoonbeamPrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 8; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// The current definition of BLOCK_STORAGE_LIMIT is 80 KB, resulting in a value of 366. + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // note: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// Parameterized slow adjusting fee updated based on +/// https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#-2.-slow-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +use frame_support::traits::FindAuthor; +//TODO It feels like this shold be able to work for any T: H160, but I tried for +// embarassingly long and couldn't figure that out. + +/// The author inherent provides a AccountId20, but pallet evm needs an H160. +/// This simple adapter makes the conversion. +pub struct FindAuthorAdapter(sp_std::marker::PhantomData); + +impl FindAuthor for FindAuthorAdapter +where + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonbeamPrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonbeam_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonbeam_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::GLMR * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonbeam_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonbeam_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_parachain_system::weights::SubstrateWeight; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<1>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 20_000 * currency::GLMR * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 500 * currency::MILLIGLMR * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonbeam_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonbeam_weights::pallet_author_inherent::WeightInfo; +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RandomnessSource = Randomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonbeam_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonbeam-"; +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonbeam_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::ConvictionVotingPrecompile + | PrecompileName::PreimagePrecompile + | PrecompileName::ReferendaPrecompile + | PrecompileName::OpenTechCommitteeInstance + | PrecompileName::TreasuryCouncilInstance + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => { + match PrecompileName::from_address(call.to.0) { + // Any precompile that can execute a subcall should be forbidden here, + // to ensure that unauthorized smart contract can't be called + // indirectly. + // To be safe, we only allow the precompiles we need. + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + // All non-whitelisted precompiles are forbidden + Some(_) => false, + // Allow evm transfer to "simple" account (no code nor precompile) + // For the moment, no smart contract other than precompiles is allowed. + // In the future, we may create a dynamic whitelist to authorize some audited + // smart contracts through governance. + None => { + // If the address is not recognized, allow only evm transfert to "simple" + // accounts (no code nor precompile). + // Note: Checking the presence of the code is not enough because some + // precompiles have no code. + !recipient_has_code + && precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + } + } + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonbeam_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonbeamMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We just want to enable this in case of live chains, since the default version + // is populated at genesis + RuntimeCall::PolkadotXcm(method) => match method { + pallet_xcm::Call::force_default_xcm_version { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<1>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonbeam_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonbeam_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonbeam_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_precompile_benchmarks::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + // System support stuff. + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 1, + // Previously 2: pallet_randomness_collective_flip + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 5, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 11, + + // Consensus support. + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 20, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 21, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 22, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 23, + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event} = 24, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 25, + + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 30, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 31, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 32, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 33, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 34, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 35, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 37, + + // Has been permanently removed for safety reasons. + // Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event} = 40, + + // Ethereum compatibility. + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 50, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 51, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 52, + + // Governance stuff. + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 60, + // Democracy: 61, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 62, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 63, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 64, + Origins: governance::custom_origins::{Origin} = 65, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 66, + + // Council stuff. + // CouncilCollective: 70 + // TechCommitteeCollective: 71 + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 72, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 73, + + // Treasury stuff. + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 80, + + // Crowdloan stuff. + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 90, + + // XCM + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event} = 100, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 101, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 102, + PolkadotXcm: pallet_xcm::{Pallet, Storage, Call, Event, Origin, Config} = 103, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 104, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 105, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 106, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Storage, Event} = 107, + // Previously 108: pallet_assets:: + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 109, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111, + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112, + + // TODO should not be included in production + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 113, + + // Randomness + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 120, + } +} + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + [pallet_relay_storage_roots, RelayStorageRoots] + ); +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to gas price from pallet ethereum. If it is any other kind of transaction, + // we modify its priority. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + // Calculate the fee that will be taken by pallet transaction payment + let fee: u64 = TransactionPayment::compute_fee( + xt.encode().len() as u32, + &dispatch_info, + tip, + ).saturated_into(); + + // Calculate how much gas this effectively uses according to the existing mapping + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + + // Here we calculate an ethereum-style effective gas price using the + // current fee of the transaction. Because the weight -> gas conversion is + // lossy, we have to handle the case where a very low weight maps to zero gas. + let effective_gas_price = if effective_gas > 0 { + fee / effective_gas + } else { + // If the effective gas was zero, we just act like it was 1. + fee + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = effective_gas_price; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 100); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(100 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(10 * MILLIGLMR)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(100 * GLMR) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(10 * GLMR + 2580 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(10 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(10 * GLMR + 530 * MILLIGLMR) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(2_000_000 * GLMR) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(50 * GLMR) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(10 * KILOGLMR) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(10 * GLMR + 80 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(210 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(10 * GLMR + 80 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(560 * MILLIGLMR) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + // This is the highest amount of new storage that can be created in a block 40 KB + let block_storage_limit = 80 * 1024; + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(block_storage_limit); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3100/runtime/moonbeam/src/migrations.rs b/tracing/3100/runtime/moonbeam/src/migrations.rs new file mode 100644 index 00000000..b3cf7c78 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/migrations.rs @@ -0,0 +1,368 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonbeam specific Migrations + +use crate::Balances; +use crate::Runtime; +use frame_support::{ + storage::unhashed::{get_raw, put_raw}, + traits::ReservableCurrency, + weights::Weight, + StorageHasher, +}; +use pallet_migrations::{GetMigrations, Migration}; +use sp_core::bytes::from_hex; +use sp_core::hex2array; +use sp_std::{prelude::*, vec}; + +pub struct MoonbeamMigrations; + +impl GetMigrations for MoonbeamMigrations { + fn get_migrations() -> Vec> { + vec![ + // Runtime 3001 + // Box::new(PalletStakingMultiplyRoundLenBy2) + // Runtime 3100 + Box::new(PalletReferendaRestoreDeposits), + ] + } +} + +// The corrupted referenda is an array of tuples containing: +// 1. the referenda index +// 2. the referenda.referendumInfoFor.key +// 3. the corrupted state +// 4. the correct state +const CORRUPTED_REFERENDA: &'static [(i32, &str, &str, &str)] = &[ + ( + 5, // referenda index + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 969e061847da7e84337ea78dc577cd1d05000000", + "0x04f5d541000101e79d1889bbd6cd8d348c5c9ad3254e92ee14e60e0000a0dec5adc9353600000000000000", + "0x04f5d5410001e79d1889bbd6cd8d348c5c9ad3254e92ee14e60e0000a0dec5adc935360000000000000000", + ), + ( + 6, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 484d257daa10da0e6fd9b5529818625c06000000", + "0x04fcd541000101381d106c440f92654827d2b2c637dd5b38a362a70000a0dec5adc9353600000000000000", + "0x04fcd5410001381d106c440f92654827d2b2c637dd5b38a362a70000a0dec5adc935360000000000000000", + ), + ( + 8, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + be1f3931028cc05c2e18a319e8f64f9e08000000", + "0x01a8ed41000000", + "0x01a8ed410001e79d1889bbd6cd8d348c5c9ad3254e92ee14e60e0000a0dec5adc935360000000000000000", + ), + ( + 9, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + f71f22775221b1945fe6cfa3c6550c7c09000000", + "0x0209d841000101e79d1889bbd6cd8d348c5c9ad3254e92ee14e60e0000a0dec5adc9353600000000000000", + "0x0209d8410001e79d1889bbd6cd8d348c5c9ad3254e92ee14e60e0000a0dec5adc935360000000000000000", + ), + ( + 13, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 7e19bf46066d74446ee15c8c2715f7030d000000", + "0x041485440001018405e969da8b4be4ab07bb712735483806f135f60000a0dec5adc9353600000000000000", + "0x0414854400018405e969da8b4be4ab07bb712735483806f135f60000a0dec5adc935360000000000000000", + ), + ( + 14, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 4671f3b0f75141e3511b3597f3223e920e000000", + "0x01c0a444000000", + "0x01c0a44400018405e969da8b4be4ab07bb712735483806f135f60000a0dec5adc935360000000000000000", + ), + ( + 20, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 264c24258678941962c0f6292ecb4cad14000000", + "0x019d5047000000", + "0x019d504700011b35a6e8cfdc01bcfc089b06a629db296aeeb2680000a0dec5adc935360000000000000000", + ), + ( + 21, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 218d19ff794c68b9ffc65f2a631525f415000000", + "0x02b8a248000101ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc9353600000000000000", + "0x02b8a2480001ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc935360000000000000000", + ), + ( + 22, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + ad1bdd11ebe8658f0084ba66824e9fe616000000", + "0x045ac548000101739c7a8f29367feb823ac1d3ac3028cc1f0ab6390000a0dec5adc9353600000000000000", + "0x045ac5480001739c7a8f29367feb823ac1d3ac3028cc1f0ab6390000a0dec5adc935360000000000000000", + ), + ( + 23, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + e9687713e18188d35299dc9fb723898417000000", + "0x0356d248000101ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc9353600000000000000", + "0x0356d2480001ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc935360000000000000000", + ), + ( + 24, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + b8a8eb3050f394da75435ac79b58aa4b18000000", + "0x01228149000000", + "0x012281490001739c7a8f29367feb823ac1d3ac3028cc1f0ab6390000a0dec5adc935360000000000000000", + ), + ( + 26, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 9ca40f4d7dc2de6440f9998e6fe95a091a000000", + "0x0112df47000000", + "0x0112df47000158ce55a4efd27f8fe836a1bcdd2bc7f0a81fa6270000a0dec5adc935360000000000000000", + ), + ( + 27, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 81a37b0404f99b797427fa89b4d07c721b000000", + "0x01a6f149000000", + "0x01a6f1490001932a2f7b446367db8284403ba5879020cce3635a0000a0dec5adc935360000000000000000", + ), + ( + 30, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 28210239547ef1b1a87a0b1c87bd80bc1e000000", + "0x0168c74b000000", + "0x0168c74b00017b9a3a0bd813c61006d94c7206137052f1cd6ce10000a0dec5adc935360000000000000000", + ), + ( + 32, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 7fbfc6805b5d0ea54a7de3ea8df2f8da20000000", + "0x01c2ca4c000000", + "0x01c2ca4c00017ba99e99bc669b3508aff9cc0a898e869459f8770000a0dec5adc935360000000000000000", + ), + ( + 37, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + ea9c3d391651517623fdb56677aed5a825000000", + "0x02847051000101bc7ce80a47ccc70eedb84267e9f0b9678f5a0c8b0000a0dec5adc9353600000000000000", + "0x028470510001bc7ce80a47ccc70eedb84267e9f0b9678f5a0c8b0000a0dec5adc935360000000000000000", + ), + ( + 38, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 2c399c11d782416ac5a2034d728fe62826000000", + "0x01ae4f53000000", + "0x01ae4f530001ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc935360000000000000001\ + 44624edd30abdc5aad29f5b233e6e610e954054f000040b2bac9e0191e02000000000000", + ), + ( + 40, + "0x0f6738a0ee80c8e74cd2c7417c1e25569613e9bbc07e304aa9a1af9b85898e5a\ + 73fecc050cc370e6185a23480f7479b128000000", + "0x01b9d253000000", + "0x01b9d2530001ee27bbebce601c882d6778a3352ffff95289493f0000a0dec5adc935360000000000000001\ + 06d2ab1ed0c25b0629d277afd6fd928d232d41b2000040b2bac9e0191e02000000000000", + ), +]; + +const INVALID_STORAGE_KEY: &[u8] = b"invalid_storage_key"; +const INVALID_VALUE_BEFORE: &[u8] = b"invalid_storage_before"; +const INVALID_VALUE_AFTER: &[u8] = b"invalid_value_after"; + +// Local assets account with reserve locked +const LOCAL_ASSET_ACCOUNT_WITH_RESERVES: [u8; 20] = + hex2array!("3fdb68f3a7f614f0f955343b63e2388fa19cd924"); +const LOCAL_ASSET_RESERVED_AMOUNT: u128 = 10_010_850_000_000_000_000_000; + +pub struct PalletReferendaRestoreDeposits; +impl Migration for PalletReferendaRestoreDeposits { + fn friendly_name(&self) -> &str { + "MM_PalletReferendaRestoreDeposits" + } + + fn migrate(&self, _available_weight: Weight) -> Weight { + // compute the hash of the expected status + let mut expected_hash: Vec = Vec::new(); + let mut actual_hash: Vec = Vec::new(); + // track reads and writes + let mut num_reads = 0; + let mut num_writes = 0; + // track the data that will be used to update the storage + let mut migration_data: Vec<(i32, Vec, Vec)> = Vec::new(); + + // compute the complete hash of the expected state (the corrupted one) + // compute the complete hash of the current state + // if they are the same, it means tha the migration must be executed + // NOTE: the referenda in the corrupted state are long closed so they cannot be updated anymore, + // if the migration runs successfully once, the state will never match the corrupted state, + // this ensures idempotence of the changes + for (ref_index, ref_storage_key, storage_value_before, storage_value_after) in + CORRUPTED_REFERENDA + { + let key = from_hex(ref_storage_key).unwrap_or_else(|_| { + log::error!("cannot deserialize from_hex(ref_storage_key)"); + INVALID_STORAGE_KEY.to_vec() + }); + + let value_before = from_hex(storage_value_before).unwrap_or_else(|_| { + log::error!("cannot deserialize from_hex(storage_value_before)"); + INVALID_VALUE_BEFORE.to_vec() + }); + + // validate also the data that will be written later + let value_after = from_hex(storage_value_after).unwrap_or(INVALID_VALUE_AFTER.to_vec()); + if value_after == INVALID_VALUE_AFTER { + log::error!("cannot deserialize from_hex(storage_value_after)"); + return ::DbWeight::get().reads(num_reads); + } + + // record the migration data + migration_data.push((*ref_index, key.clone(), value_after)); + + let data = [expected_hash, key.clone(), value_before].concat(); + expected_hash = frame_support::Blake2_256::hash(&data).to_vec(); + + let value_current = get_raw(&key); + num_reads += 1; + if value_current.is_none() { + log::error!("storage for referenda {:?} not found", ref_index); + return ::DbWeight::get().reads(num_reads); + } + + let data = [actual_hash, key, value_current.unwrap()].concat(); + actual_hash = frame_support::Blake2_256::hash(&data).to_vec(); + } + + if expected_hash != actual_hash { + // the migration was already executed, track the reads + log::warn!( + "expected partial state hash {:?} doesn't match actual {:x?}, \ + has the migration been already applied?", + sp_core::hexdisplay::HexDisplay::from(&expected_hash), + sp_core::hexdisplay::HexDisplay::from(&actual_hash), + ); + return ::DbWeight::get().reads(num_reads); + } + + log::info!( + "matched expected partial state hash {:?} with actual {:x?}", + sp_core::hexdisplay::HexDisplay::from(&expected_hash), + sp_core::hexdisplay::HexDisplay::from(&actual_hash), + ); + + // update the storage + for (ref_index, ref_storage_key, storage_value_after) in migration_data { + log::info!("restoring deposits for referenda {}", ref_index); + put_raw(&ref_storage_key, &storage_value_after); + num_writes += 1; + } + + // Second step - unlock local assets reserves + let account = + ::AccountId::from(LOCAL_ASSET_ACCOUNT_WITH_RESERVES); + Balances::unreserve(&account, LOCAL_ASSET_RESERVED_AMOUNT); + + // track the read/write + num_reads += 1; + num_writes += 1; + + ::DbWeight::get().reads_writes(num_reads, num_writes) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { + // check that the state is the one expected before runtime + for (ref_number, ref_storage_key, wrong_storage_value, _) in CORRUPTED_REFERENDA { + let key = from_hex(ref_storage_key).map_err(|_| { + sp_runtime::DispatchError::Other( + "pre_upgrade: cannot decode from_hex(ref_storage_key)", + ) + })?; + let val_expected = from_hex(wrong_storage_value).map_err(|_| { + sp_runtime::DispatchError::Other( + "pre_upgrade: cannot decode from_hex(wrong_storage_value)", + ) + })?; + let val_got = get_raw(&key).ok_or_else(|| { + log::error!("for referenda {}", ref_number); + sp_runtime::DispatchError::Other("pre_upgrade: cannot decode get_raw(&key)") + })?; + + frame_support::ensure!( + val_expected == val_got, + "pre_upgrade: unexpected storage value" + ); + } + + // check local asset reserves + // Second step - unlock local assets reserves + let account = + ::AccountId::from(LOCAL_ASSET_ACCOUNT_WITH_RESERVES); + let reserved = Balances::reserved_balance(&account); + // Returning the account info before changing the reserve value + Ok(reserved.to_le_bytes().to_vec()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(&self, state_before: Vec) -> Result<(), sp_runtime::DispatchError> { + // check that the state is the one expected before runtime + for (ref_num, ref_storage_key, _, storage_value_after) in CORRUPTED_REFERENDA { + let key = from_hex(ref_storage_key).map_err(|_| { + sp_runtime::DispatchError::Other( + "post_upgrade: cannot decode from_hex(ref_storage_key)", + ) + })?; + let val_expected = from_hex(storage_value_after).map_err(|_| { + sp_runtime::DispatchError::Other( + "post_upgrade: cannot decode from_hex(storage_value_after)", + ) + })?; + let val_got = get_raw(&key).ok_or_else(|| { + sp_runtime::DispatchError::Other("post_upgrade: cannot read get_raw(&key)") + })?; + + frame_support::ensure!( + val_expected == val_got, + "post_upgrade: unexpected storage value" + ); + log::info!("referenda {} updated correctly", ref_num); + } + + // check the reserves + let account = + ::AccountId::from(LOCAL_ASSET_ACCOUNT_WITH_RESERVES); + let reserved_after = Balances::reserved_balance(&account); + let reserved_before = u128::from_le_bytes( + state_before[..] + .try_into() + .expect("cannot read state_before"), + ); + + log::info!( + "reserve_before {}, reserve_after {}, diff {}", + reserved_before, + reserved_after, + reserved_before - reserved_after, + ); + + frame_support::ensure!( + (reserved_after + LOCAL_ASSET_RESERVED_AMOUNT) - reserved_before == 0, + "Reserve not matching" + ); + + Ok(()) + } +} diff --git a/tracing/3100/runtime/moonbeam/src/precompiles.rs b/tracing/3100/runtime/moonbeam/src/precompiles.rs new file mode 100644 index 00000000..685f292c --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/precompiles.rs @@ -0,0 +1,296 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, + Runtime, TreasuryCouncilInstance, +}; +use crate::{AssetId, H160}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_utils::precompile_set::*; +use sp_std::prelude::*; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonbeam_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +pub struct NativeErc20Metadata; + +/// ERC20 metadata for the native token. +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "GLMR token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "GLMR" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as local +pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8, 255u8, 255u8, 254u8]; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; + pub LocalAssetPrefix: &'static [u8] = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +#[precompile_utils::precompile_name_from_address] +type MoonbeamPrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2050>, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // Democracy + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract< + pallet_evm_precompile_xcm_utils::AllExceptXcmExecute, + >, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, //CouncilInstance + RemovedPrecompileAt>, // TechCommitteeInstance + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, +); + +pub struct DisabledLocalAssets(sp_std::marker::PhantomData); + +impl sp_core::Get> for DisabledLocalAssets +where + Runtime: frame_system::Config, + Runtime::AccountId: Into, + Runtime: AccountIdAssetIdConversion, +{ + fn get() -> Vec { + vec![ + 337110116006454532607322340792629567158u128, + 278750993613512357835566279094880339619, + 228256396637196286254896220398224702687, + 270195117769614861929703564202131636628, + ] + .iter() + .map(|id| Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, *id).into()) + .collect() + } +} + +/// The PrecompileSet installed in the Moonbeam runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// as well as a special precompile for dispatching Substrate extrinsics +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonbeamPrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonbeamPrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompilesAt>, + ), +>; diff --git a/tracing/3100/runtime/moonbeam/src/xcm_config.rs b/tracing/3100/runtime/moonbeam/src/xcm_config.rs new file mode 100644 index 00000000..5245ec86 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/src/xcm_config.rs @@ -0,0 +1,740 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, Erc20XcmBridge, + MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, + RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; +use sp_weights::Weight; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; + +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + FirstAssetTrader, IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, + UtilityEncodeCall, XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + // Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +pub type AssetTransactors = ( + LocalAssetTransactor, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// The amount of weight an XCM operation takes. This is safe overestimate. + pub UnitWeightCost: Weight = Weight::from_parts(200_000_000u64, 0); + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +/// We do not burn anything because we want to mimic exactly what +/// the sovereign account has +pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount< + super::Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + UsingComponents< + ::WeightToFee, + SelfReserve, + AccountId, + Balances, + DealWithFees, + >, + FirstAssetTrader, + ); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // TODO pallet-xcm weights + type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 128 * 1048; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type WeightInfo = pallet_message_queue::weights::SubstrateWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We simply hash the AssetType and take the lowest 128 bits +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // We distinguish by prefix, and depending on it we create either + // Foreign or Local + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: sp_runtime::traits::MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // Polkadot AssetHub fee + (1, Some(Parachain(1000u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 DOT should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 400_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3100/runtime/moonbeam/tests/common/mod.rs b/tracing/3100/runtime/moonbeam/tests/common/mod.rs new file mode 100644 index 00000000..3d92f80a --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/common/mod.rs @@ -0,0 +1,394 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonbeam_runtime::{ + asset_config::AssetRegistrarMetadata, currency::GLMR, xcm_config::AssetType, AccountId, + AssetId, AssetManager, AsyncBacking, AuthorInherent, Balance, Ethereum, InflationInfo, + ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter, + UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f869820501808085e8d4a51000825208943cd0a705a2dc65e5b1e1205896baa2be8a07c6e00180c\ + 001a061087911e877a5802142a89a40d231d50913db399eb50839bb2d04e612b22ec8a01aa313efdf2\ + 793bea76da6813bda611444af16a6207a8cfef2d9c8aa8f8012f7"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f8628085174876e800809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ba011110796057\ + 0e2d49fcc2afbc582e1abd3eeb027242b92abcebcec7cdefab63ea001732f6fac84acdd5b096554230\ + 75003e7f07430652c3d6722e18f50b3d34e29"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Helper function to give a simple evm context suitable for tests. +// We can remove this once https://github.com/rust-blockchain/evm/pull/35 +// is in our dependency graph. +pub fn evm_test_context() -> fp_evm::Context { + fp_evm::Context { + address: Default::default(), + caller: Default::default(), + apparent_value: From::from(0), + } +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_type: AssetType, + pub metadata: AssetRegistrarMetadata, + pub balances: Vec<(AccountId, Balance)>, + pub is_sufficient: bool, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccountId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec, is_sufficient] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * GLMR, + ideal: 200_000 * GLMR, + max: 500_000 * GLMR, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 6 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + let xcm_assets = self.xcm_assets.clone(); + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into(); + AssetManager::register_foreign_asset( + root_origin(), + xcm_asset_initialization.asset_type, + xcm_asset_initialization.metadata, + 1, + xcm_asset_initialization.is_sufficient, + ) + .unwrap(); + for (account, balance) in xcm_asset_initialization.balances { + moonbeam_runtime::Assets::mint( + origin_of(AssetManager::account_id()), + asset_id.into(), + account, + balance, + ) + .unwrap(); + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3100/runtime/moonbeam/tests/evm_tracing.rs b/tracing/3100/runtime/moonbeam/tests/evm_tracing.rs new file mode 100644 index 00000000..c47675d1 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * GLMR), + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * GLMR), + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * GLMR)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3100/runtime/moonbeam/tests/integration_test.rs b/tracing/3100/runtime/moonbeam/tests/integration_test.rs new file mode 100644 index 00000000..c52ee25f --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/integration_test.rs @@ -0,0 +1,2896 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Integration Tests + +#![cfg(test)] + +mod common; +use common::*; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{ + fungible::Inspect, Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, + StorageInfoTrait, + }, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbeam_runtime::currency::{GIGAWEI, WEI}; +use moonbeam_runtime::{ + asset_config::ForeignAssetInstance, + currency::GLMR, + xcm_config::{CurrencyId, SelfReserve}, + AccountId, Balances, CrowdloanRewards, Executive, OpenTechCommitteeCollective, + ParachainStaking, PolkadotXcm, Precompiles, Runtime, RuntimeBlockWeights, RuntimeCall, + RuntimeEvent, System, TransactionPayment, TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, XTokens, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; +use parity_scale_codec::Encode; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; +use sha3::{Digest, Keccak256}; +use sp_core::{ByteArray, Pair, H160, U256}; +use sp_runtime::{ + traits::{Convert, Dispatchable}, + BuildStorage, DispatchError, ModuleError, +}; +use std::str::from_utf8; +use xcm::latest::prelude::*; +use xcm::{VersionedAsset, VersionedAssets, VersionedLocation}; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonbeam_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +const BASE_FEE_GENESIS: u128 = 10000 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait once https://github.com/paritytech/substrate/pull/9246 + // is pulled in substrate deps. + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"Now".to_vec(), + prefix: prefix(b"Timestamp", b"Now"), + max_values: Some(1), + max_size: Some(8), + }, + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"DidUpdate".to_vec(), + prefix: prefix(b"Timestamp", b"DidUpdate"), + max_values: Some(1), + max_size: Some(1), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonbeam_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + + // System support + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + // Monetary + is_pallet_index::(10); + is_pallet_index::(11); + // Consensus support + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + // Handy utilities + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(35); + is_pallet_index::(37); + // Ethereum compatibility + is_pallet_index::(50); + is_pallet_index::(51); + is_pallet_index::(52); + // Governance + is_pallet_index::(60); + // is_pallet_index::(61); Removed + // Council + // is_pallet_index::(70); Removed + // is_pallet_index::(71); Removed + is_pallet_index::(72); + is_pallet_index::(73); + // Treasury + is_pallet_index::(80); + // Crowdloan + is_pallet_index::(90); + // XCM Stuff + is_pallet_index::(100); + is_pallet_index::(101); + is_pallet_index::(102); + is_pallet_index::(103); + is_pallet_index::(104); + is_pallet_index::(105); + is_pallet_index::(106); + is_pallet_index::(107); +} + +#[test] +fn verify_reserved_indices() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + use frame_metadata::*; + let metadata = moonbeam_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 40: Sudo + // 53: BaseFee + // 108: pallet_assets:: + let reserved = vec![40, 53, 108]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonbeam_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonbeam_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonbeam_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonbeam_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonbeam_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonbeam_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonbeam_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonbeam_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 10_000_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + (AccountId::from(CHARLIE), 10_000_000 * GLMR), + (AccountId::from(DAVE), 10_000_000 * GLMR), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 2_000_000 * GLMR), + (AccountId::from(BOB), 2_000_000 * GLMR), + ]) + .with_delegations(vec![ + ( + AccountId::from(CHARLIE), + AccountId::from(ALICE), + 5_000 * GLMR, + ), + (AccountId::from(CHARLIE), AccountId::from(BOB), 5_000 * GLMR), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 2_000_000 * GLMR, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 2_000_000 * GLMR, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 2_000_000 * GLMR, + new_total_amt_locked: 6_010_000 * GLMR + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 2_005_000 * GLMR); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 2_005_000 * GLMR); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 2_000_000 * GLMR); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 10_000_000 * GLMR)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ), + DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + // Alice transfer from free balance 3_000_000 GLMR to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 3_000_000 * GLMR, + )); + assert_eq!( + Balances::free_balance(AccountId::from(BOB)), + 3_000_000 * GLMR + ); + + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + // Bob transfers 2_000_000 GLMR to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: vec![], + value: (2_000_000 * GLMR).into(), + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 2_000_000 * GLMR); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 10k extra tokens for her mapping deposit + (AccountId::from(ALICE), 10_010_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + // Just before round 3 + run_to_block(7199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8_010_000 * GLMR, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9_950_000 * GLMR, + ); + run_to_block(7201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8990978048702400000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9969521950497200000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 10k extra tokens for her mapping deposit + (AccountId::from(ALICE), 10_010_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + (AccountId::from(CHARLIE), 10_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 3 + run_to_block(7199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no collators rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8_010_000 * GLMR, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9_950_000 * GLMR, + ); + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 310300000000000000000000, + ); + + // Go to round 3 + run_to_block(7201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // collators rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8698492682878000000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9962207316621500000000000, + ); + // 30% reserved for parachain bond again + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 615104500000000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(300_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 150_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 150_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + 45_000_000 * GLMR + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 45_000_000 * GLMR); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(ALICE)), + 43_200_000 + )] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 90, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (105_000_000 * GLMR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (45_000_000 * GLMR) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (45_000_000 * GLMR) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (45_000_000 * GLMR) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (45_000_000 * GLMR) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature is new_account || previous_account + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonbeam-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * GLMR); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * GLMR) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + assert!(CrowdloanRewards::initialized()); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * GLMR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * GLMR); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * GLMR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * GLMR) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(BOB).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * GLMR).into(); + let expected_claimed: U256 = (450_000 * GLMR).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * GLMR) + ); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonbeam_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 100_000_000_100, calc_fee(1)); + assert_eq!( 1_000_000_100_000, calc_fee(10)); + assert_eq!( 10_000_100_000_000, calc_fee(100)); + assert_eq!( 100_100_000_000_000, calc_fee(1_000)); + assert_eq!( 1_100_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 110_000_000_000_000_000, calc_fee(100_000)); + assert_eq!( 100_100_000_000_000_000_000, calc_fee(1_000_000)); // 100 GLMR, ~ 1MB + assert_eq!( 100_001_000_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(100_000_010_000_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonbeam_runtime::MinimumMultiplier::get(); + let target = moonbeam_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = moonbeam_runtime::SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 125_000_000_000u128.into(), + Weight::from_parts(25_000_000u64, 0) + ) + ); + }); +} + +#[test] +fn min_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + use frame_support::traits::Hooks; + + ExtBuilder::default().build().execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::put(Multiplier::from(0)); + TransactionPayment::on_finalize(System::block_number()); // should trigger min to kick in + + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 125_000_000_000u128.into(), + Weight::from_parts(25_000_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * GLMR) + (1 * WEI)), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * GLMR, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * GLMR) + (21_000 * BASE_FEE_GENESIS)) + (1 * WEI), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * GLMR) + (21_777 * BASE_FEE_GENESIS)), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_777u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENESIS, + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * GLMR); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * GLMR,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * (200 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(200 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(100 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 100 GWEI base fee + 100 GWEI tip. + let fee = ((200 * GIGAWEI) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbeam_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * BASE_FEE_GENESIS), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 100 GWEI base fee. + let fee = (BASE_FEE_GENESIS * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbeam_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(2) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Limited(4000000000.into()) + )); + }) +} + +#[test] +fn asset_can_be_registered() { + ExtBuilder::default().build().execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + let asset_metadata = AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }; + assert_ok!(AssetManager::register_foreign_asset( + moonbeam_runtime::RuntimeOrigin::root(), + source_location, + asset_metadata, + 1u128, + true + )); + assert!(AssetManager::asset_id_type(source_id).is_some()); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!( + moonbeam_runtime::Assets::total_supply(relay_asset_id), + 1_000 * GLMR + ); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * GLMR)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * GLMR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Aice to Bob, 400 GLMR. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(24360) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Make sure BOB has 400 GLMR + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * GLMR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 GLMR from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(14407) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(29695) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 GLMR + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * GLMR)); + }); +} + +#[test] +fn xtokens_precompile_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(57639) + .expect_no_logs() + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompile_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(57639) + .expect_no_logs() + .execute_returns(()); + }) +} + +#[test] +fn make_sure_glmr_can_be_transferred_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + assert_ok!(XTokens::transfer_multiasset( + origin_of(AccountId::from(ALICE)), + Box::new(VersionedAsset::V4(Asset { + id: AssetId(moonbeam_runtime::xcm_config::SelfReserve::get()), + fun: Fungible(1000) + })), + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(40000.into()) + )); + }); +} + +#[test] +fn make_sure_glmr_can_be_transferred() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(40000.into()) + )); + }); +} + +#[test] +fn make_sure_polkadot_xcm_cannot_be_called() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let assets: Assets = [Asset { + id: AssetId(moonbeam_runtime::xcm_config::SelfLocation::get()), + fun: Fungible(1000), + }] + .to_vec() + .into(); + assert_noop!( + RuntimeCall::PolkadotXcm(pallet_xcm::Call::::reserve_transfer_assets { + dest: Box::new(VersionedLocation::V4(dest.clone())), + beneficiary: Box::new(VersionedLocation::V4(dest)), + assets: Box::new(VersionedAssets::V4(assets)), + fee_asset_item: 0, + }) + .dispatch(::RuntimeOrigin::signed( + AccountId::from(ALICE) + )), + frame_system::Error::::CallFiltered + ); + }); +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(18748) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbeam_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 2000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbeam_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId(CurrencyId::ForeignAsset(source_id)), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn call_xtokens_with_fee() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + + let before_balance = + moonbeam_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + + // We are able to transfer with fee + assert_ok!(XTokens::transfer_with_fee( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + 100, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + )); + + let after_balance = + moonbeam_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + // At least these much (plus fees) should have been charged + assert_eq!(before_balance - 100_000_000_000_000 - 100, after_balance); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_location = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_location, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_location, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_location = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_location) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_location, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonbeam_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, + 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, + 2068, 2069, 2070, 2071, 2072, 2073, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonbeam_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * GLMR), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * GLMR)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonbeam_runtime::{ + currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_core::Get; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = 5_000u64; + let tip = 42u128; + type WeightToFeeImpl = ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = + WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee( + &Weight::from_parts(extrinsic_weight, 1), + )) + LengthToFeeImpl::weight_to_fee(&Weight::from_parts(extrinsic_len as u64, 1)) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: Weight::from_parts(extrinsic_weight, 1), + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(125_075_022_500u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(125_325_422_500u128), + ); + + // 1 "real" hour (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(179_166_172_951u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(594_851_612_166u128), + ); + + // 1 "real" day (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(125_000_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(706_665_861_883_635u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(12_500_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3100/runtime/moonbeam/tests/runtime_apis.rs b/tracing/3100/runtime/moonbeam/tests/runtime_apis.rs new file mode 100644 index 00000000..b7df77d0 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/runtime_apis.rs @@ -0,0 +1,395 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::GenesisAccount; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping, FeeCalculator}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use moonbeam_runtime::{Executive, TransactionPaymentAsGasPrice}; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * GLMR)]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * GLMR), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 2_000 * GLMR), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * GLMR)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 200_000 * GLMR), + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 200_000 * GLMR), + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} diff --git a/tracing/3100/runtime/moonbeam/tests/xcm_mock/mod.rs b/tracing/3100/runtime/moonbeam/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..d52700b8 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/xcm_mock/mod.rs @@ -0,0 +1,271 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +pub mod parachain; +pub mod relay_chain; +pub mod statemint_like; + +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemint { + Runtime = statemint_like::Runtime, + XcmpMessageHandler = statemint_like::MsgQueue, + DmpMessageHandler = statemint_like::MsgQueue, + new_ext = statemint_ext(4), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 4]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (4, Statemint), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { + use statemint_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemintBalances = pallet_balances::Pallet; +pub type StatemintChainPalletXcm = pallet_xcm::Pallet; +pub type StatemintAssets = pallet_assets::Pallet; + +pub type Assets = pallet_assets::Pallet; +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; diff --git a/tracing/3100/runtime/moonbeam/tests/xcm_mock/parachain.rs b/tracing/3100/runtime/moonbeam/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..4bdd9f2f --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/xcm_mock/parachain.rs @@ -0,0 +1,1099 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; +pub use moonbeam_runtime::xcm_config::AssetType; + +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + AssetId as XcmAssetId, Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, + FixedWeightBounds, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, + NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 1; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +pub type XcmFeesToAccount_ = xcm_primitives::XcmFeesToAccount< + Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +parameter_types! { + // We cannot skip the native trader for some specific tests, so we will have to work with + // a native trader that charges same number of units as weight + pub ParaTokensPerSecond: (XcmAssetId, u128, u128) = ( + AssetId(SelfReserve::get()), + 1000000000000, + 0, + ); +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + // We use two traders + // When we receive the self-reserve asset, + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + FixedRateOfFungible, + xcm_primitives::FirstAssetTrader, + ); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(4u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 DOT should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 80 KB. +const BLOCK_STORAGE_LIMIT: u64 = 80 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3100/runtime/moonbeam/tests/xcm_mock/relay_chain.rs b/tracing/3100/runtime/moonbeam/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..15bb49b9 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(4).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3100/runtime/moonbeam/tests/xcm_mock/statemint_like.rs b/tracing/3100/runtime/moonbeam/tests/xcm_mock/statemint_like.rs new file mode 100644 index 00000000..48a358c0 --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/xcm_mock/statemint_like.rs @@ -0,0 +1,582 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, Everything, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; + +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemint_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemint_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemint_prefix, + + } +); diff --git a/tracing/3100/runtime/moonbeam/tests/xcm_tests.rs b/tracing/3100/runtime/moonbeam/tests/xcm_tests.rs new file mode 100644 index 00000000..ff3409ab --- /dev/null +++ b/tracing/3100/runtime/moonbeam/tests/xcm_tests.rs @@ -0,0 +1,3701 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Xcm Tests + +mod xcm_mock; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use frame_support::{ + assert_ok, + traits::{PalletInfo, PalletInfoAccess}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + BoundedVec, +}; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use sp_core::ConstU32; +use sp_runtime::traits::MaybeEquivalence; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, GeneralIndex, Junction, Junctions, Limited, Location, OriginKind, + PalletInstance, Parachain, QueryResponse, Reanchorable, Response, WeightLimit, Xcm, +}; +use xcm::{VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::parachain; +use xcm_mock::relay_chain; +use xcm_mock::*; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; +use xcm_simulator::TestExt; + +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // Free execution + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // This represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // Native token is substracted in paraA + ParaA::execute_with(|| { + // Free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 12500000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because trully the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 400000000 + 3000 we should have taken out 4000003000 tokens from the caller + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let response = Response::Version(2); + let querier: Location = ([]/* Here */).into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemint_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemint_asset_a_balances = Location::new( + 1, + [ + Parachain(4), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemintToken".to_vec(), + symbol: b"StatemintToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] +fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [Parachain(4u32), PalletInstance(5u8), GeneralIndex(10u128)], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + relay_location, + 0u128, + 0 + )); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + statemint_location_asset, + 0u128, + 1 + )); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([] /* Here */, 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemint tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemint USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemint: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemint) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemint_beneficiary = Location { + parents: 1, + interior: [ + Parachain(4), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemint::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemint using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemint_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + println!("STATEMINT EVENTS: {:?}", parachain::para_events()); + // Check that BOB received 100 USDC on statemint + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp close + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3100/runtime/moonriver/Cargo.toml b/tracing/3100/runtime/moonriver/Cargo.toml new file mode 100644 index 00000000..d1575a8b --- /dev/null +++ b/tracing/3100/runtime/moonriver/Cargo.toml @@ -0,0 +1,413 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonriver Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonriver-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-debug-derive = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +precompile-utils = { workspace = true } + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +polkadot-core-primitives = { workspace = true } +polkadot-parachain = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } +pallet-message-queue = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonbeam-xcm-benchmarks/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-relay-encoder/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] + +# Must be enabled for tracing runtimes only +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Allow to print logs details (no wasm:stripped) +force-debug = ["sp-debug-derive/force-debug"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-precompile-benchmarks/try-runtime", + "pallet-preimage/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", +] diff --git a/tracing/3100/runtime/moonriver/build.rs b/tracing/3100/runtime/moonriver/build.rs new file mode 100644 index 00000000..3934b9c5 --- /dev/null +++ b/tracing/3100/runtime/moonriver/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/tracing/3100/runtime/moonriver/src/asset_config.rs b/tracing/3100/runtime/moonriver/src/asset_config.rs new file mode 100644 index 00000000..7ecc6bd1 --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/asset_config.rs @@ -0,0 +1,217 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, AssetManager, Assets, Balance, Balances, + OpenTechCommitteeInstance, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; +use frame_system::{EnsureNever, EnsureRoot}; +use sp_core::H160; + +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::MOVR * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonbeam_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} + +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonbeam_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3100/runtime/moonriver/src/governance/councils.rs b/tracing/3100/runtime/moonriver/src/governance/councils.rs new file mode 100644 index 00000000..1c51423e --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/governance/councils.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3100/runtime/moonriver/src/governance/mod.rs b/tracing/3100/runtime/moonriver/src/governance/mod.rs new file mode 100644 index 00000000..36a2c6be --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3100/runtime/moonriver/src/governance/origins.rs b/tracing/3100/runtime/moonriver/src/governance/origins.rs new file mode 100644 index 00000000..ef4675d6 --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/governance/origins.rs @@ -0,0 +1,84 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +#![cfg_attr(not(feature = "std"), no_std)] +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3100/runtime/moonriver/src/governance/referenda.rs b/tracing/3100/runtime/moonriver/src/governance/referenda.rs new file mode 100644 index 00000000..8177e88e --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/governance/referenda.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::*; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * MOVR * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +// Origin for general admin or root +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; +// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3100/runtime/moonriver/src/governance/tracks.rs b/tracing/3100/runtime/moonriver/src/governance/tracks.rs new file mode 100644 index 00000000..8dddbeca --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{KILOMOVR, MOVR, SUPPLY_FACTOR}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 100 * KILOMOVR * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 500 * MOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 10 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 20 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 500 * MOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3100/runtime/moonriver/src/lib.rs b/tracing/3100/runtime/moonriver/src/lib.rs new file mode 100644 index 00000000..f80df141 --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/lib.rs @@ -0,0 +1,1842 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonriver Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonriver tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use fp_rpc::TransactionStatus; + +// Re-export required by get! macro. +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, + ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonbeam_weights, +}; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + serde::{Deserialize, Serialize}, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, SaturatedConversion, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{ + v3::{AssetId as XcmAssetId, Location}, + IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_config::AssetType; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; +use xcm_primitives::UnitsToWeightRatio; + +use smallvec::smallvec; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use nimbus_primitives::CanAuthor; + +pub use precompiles::{ + MoonriverPrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonriverPrecompiles; + +pub mod asset_config; +pub mod governance; +pub mod xcm_config; + +mod migrations; +mod precompiles; + +pub use governance::councils::*; + +/// MOVR, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 1; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROMOVR: Balance = 1_000_000_000_000; + pub const MILLIMOVR: Balance = 1_000_000_000_000_000; + pub const MOVR: Balance = 1_000_000_000_000_000_000; + pub const KILOMOVR: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROMOVR * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * MOVR * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(2) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core datastructures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonriver"), + impl_name: create_runtime_str!("moonriver"), + authoring_version: 3, + spec_version: 3100, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 2, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The output of the `Hashing` function. + type Hash = H256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1285>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonbeam_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonbeam_weights::pallet_timestamp::WeightInfo; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonbeam_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% are burned, 20% to the treasury + let (_, to_treasury) = fees.ration(80, 20); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2000ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; + +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This low value causes changes to occur slowly over time. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + /// This value is currently only used by pallet-transaction-payment as an assertion that the + /// next multiplier is always > min value. + pub MinimumMultiplier: Multiplier = Multiplier::from(1u128); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonriverPrecompiles = MoonriverPrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 16 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 16; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// The current definition of BLOCK_STORAGE_LIMIT is 160 KB, resulting in a value of 366. + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // note: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// Parameterized slow adjusting fee updated based on +/// https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#-2.-slow-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +use frame_support::traits::FindAuthor; +//TODO It feels like this shold be able to work for any T: H160, but I tried for +// embarassingly long and couldn't figure that out. + +/// The author inherent provides a AccountId20, but pallet evm needs an H160. +/// This simple adapter makes the conversion. +pub struct FindAuthorAdapter(sp_std::marker::PhantomData); + +impl FindAuthor for FindAuthorAdapter +where + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonriverPrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonbeam_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonbeam_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::MOVR * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonbeam_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonbeam_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_parachain_system::weights::SubstrateWeight; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} + +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<2>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<24>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<24>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<24>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<24>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<24>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 500 * currency::MOVR * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 5 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonbeam_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonbeam_weights::pallet_author_inherent::WeightInfo; +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RandomnessSource = Randomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonbeam_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonriver-"; + +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonbeam_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::TreasuryCouncilInstance + | PrecompileName::PreimagePrecompile + | PrecompileName::ReferendaPrecompile + | PrecompileName::ConvictionVotingPrecompile + | PrecompileName::OpenTechCommitteeInstance + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => { + match PrecompileName::from_address(call.to.0) { + // Any precompile that can execute a subcall should be forbidden here, + // to ensure that unauthorized smart contract can't be called + // indirectly. + // To be safe, we only allow the precompiles we need. + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + // All non-whitelisted precompiles are forbidden + Some(_) => false, + // Allow evm transfer to "simple" account (no code nor precompile) + // For the moment, no smart contract other than precompiles is allowed. + // In the future, we may create a dynamic whitelist to authorize some audited + // smart contracts through governance. + None => { + // If the address is not recognized, allow only evm transfert to "simple" + // accounts (no code nor precompile). + // Note: Checking the presence of the code is not enough because some + // precompiles have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + } + } + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonbeam_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonriverMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We just want to enable this in case of live chains, since the default version + // is populated at genesis + RuntimeCall::PolkadotXcm(method) => match method { + pallet_xcm::Call::force_default_xcm_version { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<3>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonbeam_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonbeam_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonbeam_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_precompile_benchmarks::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + // System support stuff. + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 1, + // Previously 2: pallet_randomness_collective_flip + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 5, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 11, + + // Consensus support. + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 20, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 21, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 22, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 23, + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event} = 24, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 25, + + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 30, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 31, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 32, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 33, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 34, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 35, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 37, + + // Sudo was previously index 40 + + // Ethereum compatibility + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 50, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 51, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 52, + + // Governance stuff. + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 60, + // Democracy: 61, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 62, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 63, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 64, + Origins: governance::custom_origins::{Origin} = 65, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 66, + + // Council stuff. + // CouncilCollective: 70 + // TechCommitteeCollective: 71, + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 72, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 73, + + // Treasury stuff. + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 80, + + // Crowdloan stuff. + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 90, + + // XCM Stuff + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event} = 100, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 101, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 102, + PolkadotXcm: pallet_xcm::{Pallet, Storage, Call, Event, Origin, Config} = 103, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 104, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 105, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 106, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Storage, Event} = 107, + // Previously 108: pallet_assets:: + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 109, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111, + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112, + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 113, + + // Randomness + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 120, + } +} + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + [pallet_relay_storage_roots, RelayStorageRoots] + ); +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to gas price from pallet ethereum. If it is any other kind of transaction, + // we modify its priority. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + // Calculate the fee that will be taken by pallet transaction payment + let fee: u64 = TransactionPayment::compute_fee( + xt.encode().len() as u32, + &dispatch_info, + tip, + ).saturated_into(); + + // Calculate how much gas this effectively uses according to the existing mapping + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + + // Here we calculate an ethereum-style effective gas price using the + // current fee of the transaction. Because the weight -> gas conversion is + // lossy, we have to handle the case where a very low weight maps to zero gas. + let effective_gas_price = if effective_gas > 0 { + fee / effective_gas + } else { + // If the effective gas was zero, we just act like it was 1. + fee + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = effective_gas_price; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 1); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(1 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(100 * MICROMOVR)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(1 * MOVR) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(1 * MOVR + 25800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(100 * MICROMOVR) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(1 * MOVR + 5300 * MICROMOVR) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(500 * MOVR) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(5 * MOVR) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(100 * MOVR) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(1 * MOVR + 800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(2100 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(1 * MOVR + 800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(5600 * MICROMOVR) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + // This is the highest amount of new storage that can be created in a block 40 KB + let block_storage_limit = 160 * 1024; + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(block_storage_limit); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3100/runtime/moonriver/src/migrations.rs b/tracing/3100/runtime/moonriver/src/migrations.rs new file mode 100644 index 00000000..bea77819 --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/migrations.rs @@ -0,0 +1,31 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonriver specific Migrations + +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{prelude::*, vec}; + +pub struct MoonriverMigrations; + +impl GetMigrations for MoonriverMigrations { + fn get_migrations() -> Vec> { + vec![ + // Runtime 3000 + // Box::new(PalletStakingMultiplyRoundLenBy2) + ] + } +} diff --git a/tracing/3100/runtime/moonriver/src/precompiles.rs b/tracing/3100/runtime/moonriver/src/precompiles.rs new file mode 100644 index 00000000..a7106e4a --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/precompiles.rs @@ -0,0 +1,269 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, + Runtime, TreasuryCouncilInstance, +}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonriver_weights; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_utils::precompile_set::*; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonriver_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +pub struct NativeErc20Metadata; + +/// ERC20 metadata for the native token. +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "MOVR token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "MOVR" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +#[precompile_utils::precompile_name_from_address] +type MoonriverPrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2050>, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // DemocracyPrecompile + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract< + pallet_evm_precompile_xcm_utils::AllExceptXcmExecute, + >, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, //CouncilInstance + RemovedPrecompileAt>, // TechCommitteeInstance + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, +); + +/// The PrecompileSet installed in the Moonriver runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonriverPrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonriverPrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + CallableByContract, + >, + // Moonriver never had any local assets (No blacklist needed + // https://moonriver.subscan.io/event?module=localassets&event_id=created + // https://moonriver.subscan.io/event?module=localassets&event_id=forcecreated + ), +>; diff --git a/tracing/3100/runtime/moonriver/src/xcm_config.rs b/tracing/3100/runtime/moonriver/src/xcm_config.rs new file mode 100644 index 00000000..c651b664 --- /dev/null +++ b/tracing/3100/runtime/moonriver/src/xcm_config.rs @@ -0,0 +1,753 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, DealWithFees, Erc20XcmBridge, + MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem, Perbill, PolkadotXcm, Runtime, + RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury, XcmpQueue, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; +use sp_weights::Weight; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; + +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + FirstAssetTrader, IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, + UtilityEncodeCall, XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + // The universal location within the global consensus system + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + + // Self Reserve location, defines the multilocation identifying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +// These correspond to +// SelfReserve asset, both pre and post 0.9.16 +// Foreign assets +// Local assets, both pre and post 0.9.16 +// We can remove the Old reanchor once +// we import https://github.com/open-web3-stack/open-runtime-module-library/pull/708 +pub type AssetTransactors = ( + LocalAssetTransactor, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// The amount of weight an XCM operation takes. This is safe overestimate. + pub UnitWeightCost: Weight = Weight::from_parts(200_000_000u64, 0); + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +/// We do not burn anything because we want to mimic exactly what +/// the sovereign account has +pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount< + super::Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + UsingComponents< + ::WeightToFee, + SelfReserve, + AccountId, + Balances, + DealWithFees, + >, + FirstAssetTrader, + ); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // TODO pallet-xcm weights + type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 128 * 1048; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type WeightInfo = pallet_message_queue::weights::SubstrateWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We simply hash the AssetType and take the lowest 128 bits +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // A foreign asset + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // Kusama AssetHub fee + (1, Some(Parachain(1000u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 KSM should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3100/runtime/moonriver/tests/common/mod.rs b/tracing/3100/runtime/moonriver/tests/common/mod.rs new file mode 100644 index 00000000..99000bb5 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/common/mod.rs @@ -0,0 +1,401 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonriver_runtime::{ + asset_config::AssetRegistrarMetadata, currency::MOVR, xcm_config::AssetType, AccountId, + AssetId, AssetManager, AsyncBacking, AuthorInherent, Balance, Ethereum, InflationInfo, + ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter, + UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; +use pallet_transaction_payment::Multiplier; + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f86d8205018085174876e80085e8d4a5100082520894f24ff3a9cf04c71dbc94d0b566f7a27b9456\ + 6cac8080c001a0e1094e1a52520a75c0255db96132076dd0f1263089f838bea548cbdbfc64a4d19f031c\ + 92a8cb04e2d68d20a6158d542a07ac440cc8d07b6e36af02db046d92df"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f86180843b9aca00809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ca00e28ba2dd3c5a\ + 3fd467d4afd7aefb4a34b373314fff470bb9db743a84d674a0aa06e5994f2d07eafe1c37b4ce5471ca\ + ecec29011f6f5bf0b1a552c55ea348df35f"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Helper function to give a simple evm context suitable for tests. +// We can remove this once https://github.com/rust-blockchain/evm/pull/35 +// is in our dependency graph. +pub fn evm_test_context() -> fp_evm::Context { + fp_evm::Context { + address: Default::default(), + caller: Default::default(), + apparent_value: From::from(0), + } +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_type: AssetType, + pub metadata: AssetRegistrarMetadata, + pub balances: Vec<(AccountId, Balance)>, + pub is_sufficient: bool, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccoutId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec, is_sufficient] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * MOVR, + ideal: 200_000 * MOVR, + max: 500_000 * MOVR, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 2 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_transaction_payment::GenesisConfig:: { + multiplier: Multiplier::from(10u128), + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + let xcm_assets = self.xcm_assets.clone(); + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into(); + AssetManager::register_foreign_asset( + root_origin(), + xcm_asset_initialization.asset_type, + xcm_asset_initialization.metadata, + 1, + xcm_asset_initialization.is_sufficient, + ) + .unwrap(); + for (account, balance) in xcm_asset_initialization.balances { + moonriver_runtime::Assets::mint( + origin_of(AssetManager::account_id()), + asset_id.into(), + account, + balance, + ) + .unwrap(); + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3100/runtime/moonriver/tests/evm_tracing.rs b/tracing/3100/runtime/moonriver/tests/evm_tracing.rs new file mode 100644 index 00000000..79fb9265 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * MOVR)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3100/runtime/moonriver/tests/integration_test.rs b/tracing/3100/runtime/moonriver/tests/integration_test.rs new file mode 100644 index 00000000..e0751c97 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/integration_test.rs @@ -0,0 +1,2805 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Integration Tests + +#![cfg(test)] + +mod common; +use common::*; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::traits::fungible::Inspect; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, StorageInfoTrait}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use moonriver_runtime::currency::{GIGAWEI, WEI}; +use moonriver_runtime::{ + asset_config::ForeignAssetInstance, + xcm_config::{CurrencyId, SelfReserve}, + AssetId, Balances, CrowdloanRewards, Executive, OpenTechCommitteeCollective, PolkadotXcm, + Precompiles, RuntimeBlockWeights, TransactionPayment, TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, XTokens, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; +use parity_scale_codec::Encode; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; +use sha3::{Digest, Keccak256}; +use sp_core::{ByteArray, Pair, H160, U256}; +use sp_runtime::{ + traits::{Convert, Dispatchable}, + BuildStorage, DispatchError, ModuleError, +}; +use std::str::from_utf8; +use xcm::latest::prelude::*; +use xcm::{VersionedAssets, VersionedLocation}; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonriver_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +const BASE_FEE_GENESIS: u128 = 100 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait from https://github.com/paritytech/substrate/pull/9246 + // This is now available with polkadot-v0.9.9 dependencies + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"Now".to_vec(), + prefix: prefix(b"Timestamp", b"Now"), + max_values: Some(1), + max_size: Some(8), + }, + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"DidUpdate".to_vec(), + prefix: prefix(b"Timestamp", b"DidUpdate"), + max_values: Some(1), + max_size: Some(1), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonriver_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + // System support + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + // Monetary + is_pallet_index::(10); + is_pallet_index::(11); + // Consensus support + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + // Handy utilities + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(35); + is_pallet_index::(37); + // Ethereum compatibility + is_pallet_index::(50); + is_pallet_index::(51); + is_pallet_index::(52); + // Governance + is_pallet_index::(60); + // is_pallet_index::(61); Removed + // Council + // is_pallet_index::(70); Removed + // is_pallet_index::(71); Removed + is_pallet_index::(72); + is_pallet_index::(73); + // Treasury + is_pallet_index::(80); + // Crowdloan + is_pallet_index::(90); + // XCM Stuff + is_pallet_index::(100); + is_pallet_index::(101); + is_pallet_index::(102); + is_pallet_index::(103); + is_pallet_index::(104); + is_pallet_index::(105); + is_pallet_index::(106); + is_pallet_index::(107); +} + +#[test] +fn verify_reserved_indices() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + use frame_metadata::*; + let metadata = moonriver_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 40: Sudo + // 53: BaseFee + // 108: pallet_assets:: + let reserved = vec![40, 53, 108]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonriver_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonriver_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonriver_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonriver_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonriver_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonriver_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonriver_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonriver_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000 * MOVR), + (AccountId::from(BOB), 20_000 * MOVR), + (AccountId::from(CHARLIE), 10_100 * MOVR), + (AccountId::from(DAVE), 10_000 * MOVR), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 10_000 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + ]) + .with_delegations(vec![ + (AccountId::from(CHARLIE), AccountId::from(ALICE), 50 * MOVR), + (AccountId::from(CHARLIE), AccountId::from(BOB), 50 * MOVR), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 10_000 * MOVR, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 10_000 * MOVR, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 10_000 * MOVR, + new_total_amt_locked: 30_100 * MOVR + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 10_050 * MOVR); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 10_050 * MOVR); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 10_000 * MOVR); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 20_000 * MOVR)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32 + ), + DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + // Alice transfer from free balance 20000 MOVR to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 20_000 * MOVR, + )); + assert_eq!(Balances::free_balance(AccountId::from(BOB)), 20_000 * MOVR); + + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + // Bob transfers 10000 MOVR to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: vec![], + value: (10_000 * MOVR).into(), + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 10_000 * MOVR, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32, + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 10_000 * MOVR); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 20_100 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 10_000 * MOVR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + + // Just before round 3 + run_to_block(2399, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 10_100 * MOVR, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 9500 * MOVR,); + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 11547666666208000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9557333332588000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 20_100 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + (AccountId::from(CHARLIE), MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 10_000 * MOVR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 2 + run_to_block(1199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no collator rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 10_100 * MOVR, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 9500 * MOVR,); + + // Go to round 2 + run_to_block(1201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 452515000000000000000, + ); + + // Go to round 3 + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 11117700475903800000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9535834523343675000000, + ); + // 30% reserved for parachain bond again + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 910802725000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 48 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * MOVR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * MOVR); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![([4u8; 32].into(), Some(AccountId::from(ALICE)), 432000)] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 90, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 48 * WEEKS as u128; + let per_block = (1_050_000 * MOVR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (450_000 * MOVR) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (450_000 * MOVR) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature: + // WRAP_BYTES|| NetworkIdentifier|| new_account || previous_account || WRAP_BYTES + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonriver-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * MOVR); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * MOVR) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + assert!(CrowdloanRewards::initialized()); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * MOVR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * MOVR); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * MOVR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(BOB).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * MOVR).into(); + let expected_claimed: U256 = (450_000 * MOVR).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + ); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonriver_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 1_000_000_001, calc_fee(1)); + assert_eq!( 10_000_001_000, calc_fee(10)); + assert_eq!( 100_001_000_000, calc_fee(100)); + assert_eq!( 1_001_000_000_000, calc_fee(1_000)); + assert_eq!( 11_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 1_100_000_000_000_000, calc_fee(100_000)); + assert_eq!( 1_001_000_000_000_000_000, calc_fee(1_000_000)); // one MOVR, ~ 1MB + assert_eq!( 1_000_010_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonriver_runtime::MinimumMultiplier::get(); + let target = moonriver_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = + moonriver_runtime::SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(10u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 12_500_000_000u128.into(), + Weight::from_parts(25_000_000u64, 0) + ) + ); + }); +} + +#[test] +fn min_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + use frame_support::traits::Hooks; + + ExtBuilder::default().build().execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::put(Multiplier::from(0)); + TransactionPayment::on_finalize(System::block_number()); // should trigger min to kick in + + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 1_250_000_000u128.into(), + Weight::from_parts(25_000_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * MOVR) + (1 * WEI)), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * MOVR, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * MOVR) + (21_000 * BASE_FEE_GENESIS)) + (1 * WEI), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * MOVR) + (21_777 * BASE_FEE_GENESIS)), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_777u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENESIS, + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * MOVR); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * MOVR,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (2 * BASE_FEE_GENESIS)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(2u128 * BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(2u128 * BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + let fee = ((2 * BASE_FEE_GENESIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonriver_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (2 * BASE_FEE_GENESIS)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + let fee = ((1 * BASE_FEE_GENESIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonriver_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(2) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Limited(4000000000.into()) + )); + }) +} + +#[test] +fn asset_can_be_registered() { + ExtBuilder::default().build().execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + let asset_metadata = AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }; + assert_ok!(AssetManager::register_foreign_asset( + moonriver_runtime::RuntimeOrigin::root(), + source_location, + asset_metadata, + 1u128, + true + )); + assert!(AssetManager::asset_id_type(source_id).is_some()); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!( + moonriver_runtime::Assets::total_supply(relay_asset_id), + 1_000 * MOVR + ); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * MOVR)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(1000 * MOVR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Aice to Bob, 400 MOVR. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(24360) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Make sure BOB has 400 MOVR + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * MOVR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 MOVR from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(14407) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(29695) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 MOVR + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(2000) + .expect_no_logs() + .execute_returns(U256::from(400 * MOVR)); + }); +} + +#[test] +fn xtokens_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonriver_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transferS + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(57639) + .expect_no_logs() + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompiles_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(57639) + .expect_no_logs() + .execute_returns(()); + }) +} + +#[test] +fn make_sure_polkadot_xcm_cannot_be_called() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let assets: Assets = [Asset { + id: AssetId(moonriver_runtime::xcm_config::SelfLocation::get()), + fun: Fungible(1000), + }] + .to_vec() + .into(); + assert_noop!( + RuntimeCall::PolkadotXcm(pallet_xcm::Call::::reserve_transfer_assets { + dest: Box::new(VersionedLocation::V4(dest.clone())), + beneficiary: Box::new(VersionedLocation::V4(dest)), + assets: Box::new(VersionedAssets::V4(assets)), + fee_asset_item: 0, + }) + .dispatch(::RuntimeOrigin::signed( + AccountId::from(ALICE) + )), + frame_system::Error::::CallFiltered + ); + }); +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1 + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonriver_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 2000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonriver_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId(CurrencyId::ForeignAsset(source_id)), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(18748) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +#[test] +fn call_xtokens_with_fee() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + + let before_balance = + moonriver_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + + // We are able to transfer with fee + assert_ok!(XTokens::transfer_with_fee( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + 100, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ),); + + let after_balance = + moonriver_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + // At least these much (plus fees) should have been charged + assert_eq!(before_balance - 100_000_000_000_000 - 100, after_balance); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_multilocation = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_multilocation, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_multilocation, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_location = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_location) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_location, + }, + ) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonriver_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1000) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, + 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, + 2068, 2069, 2070, 2071, 2072, 2073, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonriver_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * MOVR), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * MOVR)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonriver_runtime::{ + currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_core::Get; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = Weight::from_parts(5_000u64, 1); + let tip = 42u128; + type WeightToFeeImpl = ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee(&extrinsic_weight)) + + LengthToFeeImpl::weight_to_fee(&(Weight::from_parts(extrinsic_len as u64, 1))) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: extrinsic_weight, + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(1_250_750_225u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(1_253_254_225u128), + ); + + // 1 "real" hour (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_791_661_729u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(5_948_516_121u128), + ); + + // 1 "real" day (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(1_250_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(7_066_658_618_836u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(125_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3100/runtime/moonriver/tests/runtime_apis.rs b/tracing/3100/runtime/moonriver/tests/runtime_apis.rs new file mode 100644 index 00000000..06a77942 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/runtime_apis.rs @@ -0,0 +1,398 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::{FeeCalculator, GenesisAccount}; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use moonriver_runtime::{Executive, TransactionPaymentAsGasPrice}; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * MOVR)]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * MOVR), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 2_000 * MOVR), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * MOVR)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + let result = + Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)).expect("Apply result."); + assert_eq!(result, Ok(())); + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + let result = + Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)).expect("Apply result."); + assert_eq!(result, Ok(())); + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * MOVR), + (AccountId::from(BOB), 10_000_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} diff --git a/tracing/3100/runtime/moonriver/tests/xcm_mock/mod.rs b/tracing/3100/runtime/moonriver/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..8d5d6e8c --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/xcm_mock/mod.rs @@ -0,0 +1,273 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +pub mod parachain; +pub mod relay_chain; +pub mod statemine_like; + +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemine { + Runtime = statemine_like::Runtime, + XcmpMessageHandler = statemine_like::MsgQueue, + DmpMessageHandler = statemine_like::MsgQueue, + new_ext = statemine_ext(4), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 4]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (4, Statemine), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemine_ext(para_id: u32) -> sp_io::TestExternalities { + use statemine_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemineBalances = pallet_balances::Pallet; +pub type StatemineChainPalletXcm = pallet_xcm::Pallet; +pub type StatemineAssets = pallet_assets::Pallet; + +pub type ParachainPalletXcm = pallet_xcm::Pallet; +pub type Assets = pallet_assets::Pallet; + +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; diff --git a/tracing/3100/runtime/moonriver/tests/xcm_mock/parachain.rs b/tracing/3100/runtime/moonriver/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..4a7f38e1 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/xcm_mock/parachain.rs @@ -0,0 +1,1105 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + AssetId as XcmAssetId, Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, + FixedWeightBounds, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, + NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +pub use moonriver_runtime::xcm_config::AssetType; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 1; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use both transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); + +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +/// This is the struct that will handle the revenue from xcm fees +pub type XcmFeesToAccount_ = xcm_primitives::XcmFeesToAccount< + Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + AccountId, + XcmFeesAccount, +>; + +parameter_types! { + // We cannot skip the native trader for some specific tests, so we will have to work with + // a native trader that charges same number of units as weight + pub ParaTokensPerSecond: (XcmAssetId, u128, u128) = ( + AssetId(SelfReserve::get()), + 1000000000000, + 0, + ); +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + // We use three traders + // When we receive either representation of the self-reserve asset, + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = ( + FixedRateOfFungible, + xcm_primitives::FirstAssetTrader, + ); + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(4u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 KSM should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 160 KB. +const BLOCK_STORAGE_LIMIT: u64 = 160 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3100/runtime/moonriver/tests/xcm_mock/relay_chain.rs b/tracing/3100/runtime/moonriver/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..15bb49b9 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(4).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3100/runtime/moonriver/tests/xcm_mock/statemine_like.rs b/tracing/3100/runtime/moonriver/tests/xcm_mock/statemine_like.rs new file mode 100644 index 00000000..61684505 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/xcm_mock/statemine_like.rs @@ -0,0 +1,582 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, Everything, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; + +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemine_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemine_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemine_prefix, + + } +); diff --git a/tracing/3100/runtime/moonriver/tests/xcm_tests.rs b/tracing/3100/runtime/moonriver/tests/xcm_tests.rs new file mode 100644 index 00000000..2ca25f55 --- /dev/null +++ b/tracing/3100/runtime/moonriver/tests/xcm_tests.rs @@ -0,0 +1,4010 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Xcm Tests + +mod xcm_mock; +use frame_support::{ + assert_ok, + traits::{PalletInfo, PalletInfoAccess}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + BoundedVec, +}; +use sp_core::ConstU32; +use sp_runtime::traits::MaybeEquivalence; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, All, BuyExecution, ClearOrigin, DepositAsset, GeneralIndex, + Junction, Junctions, Limited, Location, OriginKind, PalletInstance, Parachain, QueryResponse, + Reanchorable, Response, WeightLimit, WithdrawAsset, Xcm, +}; +use xcm::{VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::parachain; +use xcm_mock::relay_chain; +use xcm_mock::*; +use xcm_simulator::TestExt; +mod common; +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; + +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // Register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // free execution + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // First send relay chain asset to Parachain A like in previous test + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // This represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Native token is substracted in paraA + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location.clone(), + 0u128, + 0 + )); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // Para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A asset has been credited + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 12500000u128, + 0 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because trully the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 2500000000000u128, + 0 + )); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 1u128, + 0 + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + let response = Response::Version(2); + let querier: Location = ([]/* Here */).into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_para_b() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + let response = Response::Version(2); + let querier: Location = [] /* Here */ + .into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + + ParaA::execute_with(|| { + // advertised version + parachain::XcmVersioner::set_version(2); + }); + + ParaB::execute_with(|| { + // Let's try with v0 + parachain::XcmVersioner::set_version(0); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + ParaA::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(ParachainPalletXcm::force_default_xcm_version( + parachain::RuntimeOrigin::root(), + Some(2) + )); + // Wrap version, which sets VersionedStorage + assert_ok!(::wrap_version( + &Location::new(1, [Parachain(2)]).into(), + mock_message + )); + + parachain::para_roll_to(2); + + // queries should have been updated + assert!(ParachainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 0, + } + .into(); + + ParaA::execute_with(|| { + // Assert that the events vector contains the version change + assert!(parachain::para_events().contains(&expected_supported_version)); + }); + + // Let's ensure talking in v0 works + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaB::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in para A + let expected_supported_version_2: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 2, + } + .into(); + + // Para A should have received the version change + ParaA::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(parachain::para_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemine_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemine_asset_a_balances = Location::new( + 1, + [ + Parachain(4), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemineToken".to_vec(), + symbol: b"StatemineToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + source_location, + 0u128, + 0 + )); + }); + + Statemine::execute_with(|| { + // Set new prefix + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] +fn send_statemint_asset_from_para_a_to_statemine_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemine asset + let statemine_asset = Location::new( + 1, + [Parachain(4u32), PalletInstance(5u8), GeneralIndex(10u128)], + ); + let statemine_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset).expect("convert to v3"), + ); + let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into(); + + let asset_metadata_statemine_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + relay_location, + 0u128, + 0 + )); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemine_location_asset.clone(), + asset_metadata_statemine_asset, + 1u128, + true + )); + assert_ok!(AssetManager::set_asset_units_per_second( + parachain::RuntimeOrigin::root(), + statemine_location_asset, + 0u128, + 1 + )); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([] /* Here */, 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemine::execute_with(|| { + // Set new prefix + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemine tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemine USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemint: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemint) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemine_beneficiary = Location { + parents: 1, + interior: [ + Parachain(4), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemine::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemine using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemine_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemine_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that BOB received 100 USDC on statemine + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get().1 as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp close + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3100/rust-toolchain b/tracing/3100/rust-toolchain new file mode 100644 index 00000000..47a114dc --- /dev/null +++ b/tracing/3100/rust-toolchain @@ -0,0 +1,5 @@ +[toolchain] +channel = "1.77.0" +components = [ "rustfmt", "clippy", "rust-src" ] +targets = [ "wasm32-unknown-unknown" ] +profile = "minimal" diff --git a/tracing/3100/shared/primitives/ext/Cargo.toml b/tracing/3100/shared/primitives/ext/Cargo.toml new file mode 100644 index 00000000..fc6bbf5e --- /dev/null +++ b/tracing/3100/shared/primitives/ext/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "moonbeam-primitives-ext" +version = '0.1.0' +authors = ['PureStake'] +edition = '2018' +homepage = 'https://moonbeam.network' +license = 'GPL-3.0-only' +repository = 'https://github.com/PureStake/moonbeam/' + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethereum-types = { workspace = true } + +# Moonbeam +evm-tracing-events = { workspace = true } + +# Substrate +parity-scale-codec = { workspace = true } +sp-runtime-interface = { workspace = true } +sp-externalities = { workspace = true } +sp-std = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "ethereum-types/std", + "evm-tracing-events/std", + "sp-runtime-interface/std", + "sp-externalities/std", + "sp-std/std", +] \ No newline at end of file diff --git a/tracing/3100/shared/primitives/ext/src/lib.rs b/tracing/3100/shared/primitives/ext/src/lib.rs new file mode 100644 index 00000000..2e0fe897 --- /dev/null +++ b/tracing/3100/shared/primitives/ext/src/lib.rs @@ -0,0 +1,82 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Environmental-aware externalities for EVM tracing in Wasm runtime. This enables +//! capturing the - potentially large - trace output data in the host and keep +//! a low memory footprint in `--execution=wasm`. +//! +//! - The original trace Runtime Api call is wrapped `using` environmental (thread local). +//! - Arguments are scale-encoded known types in the host. +//! - Host functions will decode the input and emit an event `with` environmental. + +#![cfg_attr(not(feature = "std"), no_std)] +use sp_runtime_interface::runtime_interface; + +use parity_scale_codec::Decode; +use sp_std::vec::Vec; + +use evm_tracing_events::{Event, EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter}; + +#[runtime_interface] +pub trait MoonbeamExt { + fn raw_step(&mut self, _data: Vec) {} + + fn raw_gas(&mut self, _data: Vec) {} + + fn raw_return_value(&mut self, _data: Vec) {} + + fn call_list_entry(&mut self, _index: u32, _value: Vec) {} + + fn call_list_new(&mut self) {} + + // New design, proxy events. + /// An `Evm` event proxied by the Moonbeam runtime to this host function. + /// evm -> moonbeam_runtime -> host. + fn evm_event(&mut self, event: Vec) { + if let Ok(event) = EvmEvent::decode(&mut &event[..]) { + Event::Evm(event).emit(); + } + } + + /// A `Gasometer` event proxied by the Moonbeam runtime to this host function. + /// evm_gasometer -> moonbeam_runtime -> host. + fn gasometer_event(&mut self, event: Vec) { + if let Ok(event) = GasometerEvent::decode(&mut &event[..]) { + Event::Gasometer(event).emit(); + } + } + + /// A `Runtime` event proxied by the Moonbeam runtime to this host function. + /// evm_runtime -> moonbeam_runtime -> host. + fn runtime_event(&mut self, event: Vec) { + if let Ok(event) = RuntimeEvent::decode(&mut &event[..]) { + Event::Runtime(event).emit(); + } + } + + /// Allow the tracing module in the runtime to know how to filter Step event + /// content, as cloning the entire data is expensive and most of the time + /// not necessary. + fn step_event_filter(&self) -> StepEventFilter { + evm_tracing_events::step_event_filter().unwrap_or_default() + } + + /// An event to create a new CallList (currently a new transaction when tracing a block). + #[version(2)] + fn call_list_new(&mut self) { + Event::CallListNew().emit(); + } +} diff --git a/tracing/3100/shared/primitives/rpc/debug/Cargo.toml b/tracing/3100/shared/primitives/rpc/debug/Cargo.toml new file mode 100644 index 00000000..1dd84780 --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/debug/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "moonbeam-rpc-primitives-debug" +authors = [ "PureStake" ] +edition = "2018" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +repository = "https://github.com/PureStake/moonbeam/" +version = "0.1.0" + +[dependencies] +environmental = { workspace = true } +ethereum = { workspace = true, features = [ "with-codec" ] } +ethereum-types = { workspace = true } +hex = { workspace = true, optional = true, features = [ "serde" ] } +serde = { workspace = true, optional = true, features = [ "derive" ] } + +# Substrate +parity-scale-codec = { workspace = true } +sp-api = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +[features] +default = [ "std" ] + +before_700 = [] +_700_to_1200 = [] +runtime-2900 = [] +runtime-3000 = [] + +std = [ + "parity-scale-codec/std", + "environmental/std", + "ethereum-types/std", + "ethereum/std", + "hex", + "serde", + "sp-api/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/tracing/3100/shared/primitives/rpc/debug/src/lib.rs b/tracing/3100/shared/primitives/rpc/debug/src/lib.rs new file mode 100644 index 00000000..b66a4f9b --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/debug/src/lib.rs @@ -0,0 +1,129 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +use parity_scale_codec::{Decode, Encode}; + +#[cfg(feature = "before_700")] +use ethereum::Transaction; +#[cfg(feature = "_700_to_1200")] +use ethereum::TransactionV0 as Transaction; +#[cfg(all(not(feature = "before_700"), not(feature = "_700_to_1200")))] +use ethereum::TransactionV2 as Transaction; + +use ethereum_types::{H160, H256, U256}; +use sp_std::vec::Vec; + +#[cfg(feature = "runtime-3000")] +sp_api::decl_runtime_apis! { + #[api_version(6)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_call( + header: &Block::Header, + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Option)>>, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(feature = "runtime-2900")] +sp_api::decl_runtime_apis! { + #[api_version(5)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(all( + not(feature = "before_700"), + not(feature = "_700_to_1200"), + not(feature = "runtime-2900"), + not(feature = "runtime-3000") +))] +sp_api::decl_runtime_apis! { + #[api_version(4)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(any(feature = "before_700", feature = "_700_to_1200"))] +sp_api::decl_runtime_apis! { + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode)] +pub enum TracerInput { + None, + Blockscout, + CallTracer, +} + +/// DebugRuntimeApi V2 result. Trace response is stored in client and runtime api call response is +/// empty. +#[derive(Debug)] +pub enum Response { + Single, + Block, +} diff --git a/tracing/3100/shared/primitives/rpc/evm-tracing-events/Cargo.toml b/tracing/3100/shared/primitives/rpc/evm-tracing-events/Cargo.toml new file mode 100644 index 00000000..d94d74a4 --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/evm-tracing-events/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "evm-tracing-events" +version = '0.1.0' +authors = ['PureStake'] +edition = '2018' +homepage = 'https://moonbeam.network' +license = 'GPL-3.0-only' +repository = 'https://github.com/PureStake/moonbeam/' + +[dependencies] +parity-scale-codec = { workspace = true } +sp-runtime-interface = { workspace = true } + +ethereum = { workspace = true, features = ["with-codec"] } +ethereum-types = { workspace = true } + +environmental = { workspace = true } + +evm = { workspace = true, features = ["with-codec"] } +evm-runtime = { workspace = true } +evm-gasometer = { workspace = true } + +[features] +default = ["std"] + +evm-tracing = ["evm/tracing", "evm-runtime/tracing", "evm-gasometer/tracing"] +std = [ + "parity-scale-codec/std", + "ethereum/std", + "ethereum-types/std", + "environmental/std", + "evm/std", + "evm-runtime/std", + "evm-gasometer/std", +] + +runtime-1600 = [] \ No newline at end of file diff --git a/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/evm.rs b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/evm.rs new file mode 100644 index 00000000..a5ac04ee --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/evm.rs @@ -0,0 +1,258 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +extern crate alloc; + +use alloc::vec::Vec; +use ethereum_types::{H160, H256, U256}; +use evm::ExitReason; +use parity_scale_codec::{Decode, Encode}; + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Transfer { + /// Source address. + pub source: H160, + /// Target address. + pub target: H160, + /// Transfer value. + pub value: U256, +} + +impl From for Transfer { + fn from(i: evm_runtime::Transfer) -> Self { + Self { + source: i.source, + target: i.target, + value: i.value, + } + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode)] +pub enum CreateScheme { + /// Legacy create scheme of `CREATE`. + Legacy { + /// Caller of the create. + caller: H160, + }, + /// Create scheme of `CREATE2`. + Create2 { + /// Caller of the create. + caller: H160, + /// Code hash. + code_hash: H256, + /// Salt. + salt: H256, + }, + /// Create at a fixed location. + Fixed(H160), +} + +impl From for CreateScheme { + fn from(i: evm_runtime::CreateScheme) -> Self { + match i { + evm_runtime::CreateScheme::Legacy { caller } => Self::Legacy { caller }, + evm_runtime::CreateScheme::Create2 { + caller, + code_hash, + salt, + } => Self::Create2 { + caller, + code_hash, + salt, + }, + evm_runtime::CreateScheme::Fixed(address) => Self::Fixed(address), + } + } +} + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] +pub enum EvmEvent { + Call { + code_address: H160, + transfer: Option, + input: Vec, + target_gas: Option, + is_static: bool, + context: super::Context, + }, + Create { + caller: H160, + address: H160, + scheme: CreateScheme, + value: U256, + init_code: Vec, + target_gas: Option, + }, + Suicide { + address: H160, + target: H160, + balance: U256, + }, + Exit { + reason: ExitReason, + return_value: Vec, + }, + TransactCall { + caller: H160, + address: H160, + value: U256, + data: Vec, + gas_limit: u64, + }, + TransactCreate { + caller: H160, + value: U256, + init_code: Vec, + gas_limit: u64, + address: H160, + }, + TransactCreate2 { + caller: H160, + value: U256, + init_code: Vec, + salt: H256, + gas_limit: u64, + address: H160, + }, + PrecompileSubcall { + code_address: H160, + transfer: Option, + input: Vec, + target_gas: Option, + is_static: bool, + context: super::Context, + }, +} + +#[cfg(feature = "evm-tracing")] +impl<'a> From> for EvmEvent { + fn from(i: evm::tracing::Event<'a>) -> Self { + match i { + evm::tracing::Event::Call { + code_address, + transfer, + input, + target_gas, + is_static, + context, + } => Self::Call { + code_address, + transfer: if let Some(transfer) = transfer { + Some(transfer.clone().into()) + } else { + None + }, + input: input.to_vec(), + target_gas, + is_static, + context: context.clone().into(), + }, + evm::tracing::Event::Create { + caller, + address, + scheme, + value, + init_code, + target_gas, + } => Self::Create { + caller, + address, + scheme: scheme.into(), + value, + init_code: init_code.to_vec(), + target_gas, + }, + evm::tracing::Event::Suicide { + address, + target, + balance, + } => Self::Suicide { + address, + target, + balance, + }, + evm::tracing::Event::Exit { + reason, + return_value, + } => Self::Exit { + reason: reason.clone(), + return_value: return_value.to_vec(), + }, + evm::tracing::Event::TransactCall { + caller, + address, + value, + data, + gas_limit, + } => Self::TransactCall { + caller, + address, + value, + data: data.to_vec(), + gas_limit, + }, + evm::tracing::Event::TransactCreate { + caller, + value, + init_code, + gas_limit, + address, + } => Self::TransactCreate { + caller, + value, + init_code: init_code.to_vec(), + gas_limit, + address, + }, + evm::tracing::Event::TransactCreate2 { + caller, + value, + init_code, + salt, + gas_limit, + address, + } => Self::TransactCreate2 { + caller, + value, + init_code: init_code.to_vec(), + salt, + gas_limit, + address, + }, + #[cfg(feature = "runtime-1600")] + evm::tracing::Event::PrecompileSubcall { + code_address, + transfer, + input, + target_gas, + is_static, + context, + } => Self::PrecompileSubcall { + code_address, + transfer: if let Some(transfer) = transfer { + Some(transfer.clone().into()) + } else { + None + }, + input: input.to_vec(), + target_gas, + is_static, + context: context.clone().into(), + }, + } + } +} diff --git a/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs new file mode 100644 index 00000000..33a6f724 --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use parity_scale_codec::{Decode, Encode}; + +#[derive(Debug, Default, Copy, Clone, Encode, Decode, PartialEq, Eq)] +pub struct Snapshot { + pub gas_limit: u64, + pub memory_gas: u64, + pub used_gas: u64, + pub refunded_gas: i64, +} + +impl Snapshot { + pub fn gas(&self) -> u64 { + self.gas_limit - self.used_gas - self.memory_gas + } +} + +impl From for Snapshot { + fn from(snapshot: evm_gasometer::Snapshot) -> Self { + Self { + gas_limit: snapshot.gas_limit, + memory_gas: snapshot.memory_gas, + used_gas: snapshot.used_gas, + refunded_gas: snapshot.refunded_gas, + } + } +} + +impl From> for Snapshot { + fn from(snapshot_opt: Option) -> Self { + if let Some(snapshot) = snapshot_opt { + snapshot.into() + } else { + Snapshot::default() + } + } +} + +#[derive(Debug, Copy, Clone, Encode, Decode, PartialEq, Eq)] +pub enum GasometerEvent { + RecordCost { + cost: u64, + snapshot: Snapshot, + }, + RecordRefund { + refund: i64, + snapshot: Snapshot, + }, + RecordStipend { + stipend: u64, + snapshot: Snapshot, + }, + RecordDynamicCost { + gas_cost: u64, + memory_gas: u64, + gas_refund: i64, + snapshot: Snapshot, + }, + RecordTransaction { + cost: u64, + snapshot: Snapshot, + }, +} + +#[cfg(feature = "evm-tracing")] +impl From for GasometerEvent { + fn from(i: evm_gasometer::tracing::Event) -> Self { + match i { + evm_gasometer::tracing::Event::RecordCost { cost, snapshot } => Self::RecordCost { + cost, + snapshot: snapshot.into(), + }, + evm_gasometer::tracing::Event::RecordRefund { refund, snapshot } => { + Self::RecordRefund { + refund, + snapshot: snapshot.into(), + } + } + evm_gasometer::tracing::Event::RecordStipend { stipend, snapshot } => { + Self::RecordStipend { + stipend, + snapshot: snapshot.into(), + } + } + evm_gasometer::tracing::Event::RecordDynamicCost { + gas_cost, + memory_gas, + gas_refund, + snapshot, + } => Self::RecordDynamicCost { + gas_cost, + memory_gas, + gas_refund, + snapshot: snapshot.into(), + }, + evm_gasometer::tracing::Event::RecordTransaction { cost, snapshot } => { + Self::RecordTransaction { + cost, + snapshot: snapshot.into(), + } + } + } + } +} diff --git a/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/lib.rs b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/lib.rs new file mode 100644 index 00000000..68714acd --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/lib.rs @@ -0,0 +1,287 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! A Proxy in this context is an environmental trait implementor meant to be used for capturing +//! EVM trace events sent to a Host function from the Runtime. Works like: +//! - Runtime Api call `using` environmental. +//! - Runtime calls a Host function with some scale-encoded Evm event. +//! - Host function emits an additional event to this Listener. +//! - Proxy listens for the event and format the actual trace response. +//! +//! There are two proxy types: `Raw` and `CallList`. +//! - `Raw` - used for opcode-level traces. +//! - `CallList` - used for block tracing (stack of call stacks) and custom tracing outputs. +//! +//! The EVM event types may contain references and not implement Encode/Decode. +//! This module provide mirror types and conversion into them from the original events. + +#![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +pub mod evm; +pub mod gasometer; +pub mod runtime; + +pub use self::evm::EvmEvent; +pub use gasometer::GasometerEvent; +pub use runtime::RuntimeEvent; + +use ::evm::Opcode; +use alloc::vec::Vec; +use ethereum_types::{H160, U256}; +use parity_scale_codec::{Decode, Encode}; +use sp_runtime_interface::pass_by::PassByCodec; + +environmental::environmental!(listener: dyn Listener + 'static); + +pub fn using R>(l: &mut (dyn Listener + 'static), f: F) -> R { + listener::using(l, f) +} + +/// Allow to configure which data of the Step event +/// we want to keep or discard. Not discarding the data requires cloning the data +/// in the runtime which have a significant cost for each step. +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode, Default, PassByCodec)] +pub struct StepEventFilter { + pub enable_stack: bool, + pub enable_memory: bool, +} + +#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)] +pub enum Event { + Evm(evm::EvmEvent), + Gasometer(gasometer::GasometerEvent), + Runtime(runtime::RuntimeEvent), + CallListNew(), +} + +impl Event { + /// Access the global reference and call it's `event` method, passing the `Event` itself as + /// argument. + /// + /// This only works if we are `using` a global reference to a `Listener` implementor. + pub fn emit(self) { + listener::with(|listener| listener.event(self)); + } +} + +/// Main trait to proxy emitted messages. +/// Used 2 times : +/// - Inside the runtime to proxy the events throught the host functions +/// - Inside the client to forward those events to the client listener. +pub trait Listener { + fn event(&mut self, event: Event); + + /// Allow the runtime to know which data should be discarded and not cloned. + /// WARNING: It is only called once when the runtime tracing is instanciated to avoid + /// performing many ext calls. + fn step_event_filter(&self) -> StepEventFilter; +} + +pub fn step_event_filter() -> Option { + let mut filter = None; + listener::with(|listener| filter = Some(listener.step_event_filter())); + filter +} + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Context { + /// Execution address. + pub address: H160, + /// Caller of the EVM. + pub caller: H160, + /// Apparent value of the EVM. + pub apparent_value: U256, +} + +impl From for Context { + fn from(i: evm_runtime::Context) -> Self { + Self { + address: i.address, + caller: i.caller, + apparent_value: i.apparent_value, + } + } +} + +/// Converts an Opcode into its name, stored in a `Vec`. +pub fn opcodes_string(opcode: Opcode) -> Vec { + let tmp; + let out = match opcode { + Opcode(0) => "Stop", + Opcode(1) => "Add", + Opcode(2) => "Mul", + Opcode(3) => "Sub", + Opcode(4) => "Div", + Opcode(5) => "SDiv", + Opcode(6) => "Mod", + Opcode(7) => "SMod", + Opcode(8) => "AddMod", + Opcode(9) => "MulMod", + Opcode(10) => "Exp", + Opcode(11) => "SignExtend", + Opcode(16) => "Lt", + Opcode(17) => "Gt", + Opcode(18) => "Slt", + Opcode(19) => "Sgt", + Opcode(20) => "Eq", + Opcode(21) => "IsZero", + Opcode(22) => "And", + Opcode(23) => "Or", + Opcode(24) => "Xor", + Opcode(25) => "Not", + Opcode(26) => "Byte", + Opcode(27) => "Shl", + Opcode(28) => "Shr", + Opcode(29) => "Sar", + Opcode(32) => "Keccak256", + Opcode(48) => "Address", + Opcode(49) => "Balance", + Opcode(50) => "Origin", + Opcode(51) => "Caller", + Opcode(52) => "CallValue", + Opcode(53) => "CallDataLoad", + Opcode(54) => "CallDataSize", + Opcode(55) => "CallDataCopy", + Opcode(56) => "CodeSize", + Opcode(57) => "CodeCopy", + Opcode(58) => "GasPrice", + Opcode(59) => "ExtCodeSize", + Opcode(60) => "ExtCodeCopy", + Opcode(61) => "ReturnDataSize", + Opcode(62) => "ReturnDataCopy", + Opcode(63) => "ExtCodeHash", + Opcode(64) => "BlockHash", + Opcode(65) => "Coinbase", + Opcode(66) => "Timestamp", + Opcode(67) => "Number", + Opcode(68) => "Difficulty", + Opcode(69) => "GasLimit", + Opcode(70) => "ChainId", + Opcode(80) => "Pop", + Opcode(81) => "MLoad", + Opcode(82) => "MStore", + Opcode(83) => "MStore8", + Opcode(84) => "SLoad", + Opcode(85) => "SStore", + Opcode(86) => "Jump", + Opcode(87) => "JumpI", + Opcode(88) => "GetPc", + Opcode(89) => "MSize", + Opcode(90) => "Gas", + Opcode(91) => "JumpDest", + Opcode(92) => "TLoad", + Opcode(93) => "TStore", + Opcode(94) => "MCopy", + Opcode(96) => "Push1", + Opcode(97) => "Push2", + Opcode(98) => "Push3", + Opcode(99) => "Push4", + Opcode(100) => "Push5", + Opcode(101) => "Push6", + Opcode(102) => "Push7", + Opcode(103) => "Push8", + Opcode(104) => "Push9", + Opcode(105) => "Push10", + Opcode(106) => "Push11", + Opcode(107) => "Push12", + Opcode(108) => "Push13", + Opcode(109) => "Push14", + Opcode(110) => "Push15", + Opcode(111) => "Push16", + Opcode(112) => "Push17", + Opcode(113) => "Push18", + Opcode(114) => "Push19", + Opcode(115) => "Push20", + Opcode(116) => "Push21", + Opcode(117) => "Push22", + Opcode(118) => "Push23", + Opcode(119) => "Push24", + Opcode(120) => "Push25", + Opcode(121) => "Push26", + Opcode(122) => "Push27", + Opcode(123) => "Push28", + Opcode(124) => "Push29", + Opcode(125) => "Push30", + Opcode(126) => "Push31", + Opcode(127) => "Push32", + Opcode(128) => "Dup1", + Opcode(129) => "Dup2", + Opcode(130) => "Dup3", + Opcode(131) => "Dup4", + Opcode(132) => "Dup5", + Opcode(133) => "Dup6", + Opcode(134) => "Dup7", + Opcode(135) => "Dup8", + Opcode(136) => "Dup9", + Opcode(137) => "Dup10", + Opcode(138) => "Dup11", + Opcode(139) => "Dup12", + Opcode(140) => "Dup13", + Opcode(141) => "Dup14", + Opcode(142) => "Dup15", + Opcode(143) => "Dup16", + Opcode(144) => "Swap1", + Opcode(145) => "Swap2", + Opcode(146) => "Swap3", + Opcode(147) => "Swap4", + Opcode(148) => "Swap5", + Opcode(149) => "Swap6", + Opcode(150) => "Swap7", + Opcode(151) => "Swap8", + Opcode(152) => "Swap9", + Opcode(153) => "Swap10", + Opcode(154) => "Swap11", + Opcode(155) => "Swap12", + Opcode(156) => "Swap13", + Opcode(157) => "Swap14", + Opcode(158) => "Swap15", + Opcode(159) => "Swap16", + Opcode(160) => "Log0", + Opcode(161) => "Log1", + Opcode(162) => "Log2", + Opcode(163) => "Log3", + Opcode(164) => "Log4", + Opcode(176) => "JumpTo", + Opcode(177) => "JumpIf", + Opcode(178) => "JumpSub", + Opcode(180) => "JumpSubv", + Opcode(181) => "BeginSub", + Opcode(182) => "BeginData", + Opcode(184) => "ReturnSub", + Opcode(185) => "PutLocal", + Opcode(186) => "GetLocal", + Opcode(225) => "SLoadBytes", + Opcode(226) => "SStoreBytes", + Opcode(227) => "SSize", + Opcode(240) => "Create", + Opcode(241) => "Call", + Opcode(242) => "CallCode", + Opcode(243) => "Return", + Opcode(244) => "DelegateCall", + Opcode(245) => "Create2", + Opcode(250) => "StaticCall", + Opcode(252) => "TxExecGas", + Opcode(253) => "Revert", + Opcode(254) => "Invalid", + Opcode(255) => "SelfDestruct", + Opcode(n) => { + tmp = alloc::format!("Unknown({})", n); + &tmp + } + }; + out.as_bytes().to_vec() +} diff --git a/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/runtime.rs b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/runtime.rs new file mode 100644 index 00000000..d9ba718d --- /dev/null +++ b/tracing/3100/shared/primitives/rpc/evm-tracing-events/src/runtime.rs @@ -0,0 +1,156 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +extern crate alloc; + +use super::{opcodes_string, Context, StepEventFilter}; +use alloc::vec::Vec; +use ethereum_types::{H160, H256, U256}; +pub use evm::{ExitError, ExitReason, ExitSucceed, Opcode}; +use parity_scale_codec::{Decode, Encode}; + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Stack { + pub data: Vec, + pub limit: u64, +} + +impl From<&evm::Stack> for Stack { + fn from(i: &evm::Stack) -> Self { + Self { + data: i.data().clone(), + limit: i.limit() as u64, + } + } +} + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Memory { + pub data: Vec, + pub effective_len: U256, + pub limit: u64, +} + +impl From<&evm::Memory> for Memory { + fn from(i: &evm::Memory) -> Self { + Self { + data: i.data().clone(), + effective_len: i.effective_len(), + limit: i.limit() as u64, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Encode, Decode)] +pub enum Capture { + /// The machine has exited. It cannot be executed again. + Exit(E), + /// The machine has trapped. It is waiting for external information, and can + /// be executed again. + Trap(T), +} + +pub type Trap = Vec; // Should hold the marshalled Opcode. + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] +pub enum RuntimeEvent { + Step { + context: Context, + // This needs to be marshalled in the runtime no matter what. + opcode: Vec, + // We can use ExitReason with `with-codec` feature, + position: Result, + stack: Option, + memory: Option, + }, + StepResult { + result: Result<(), Capture>, + return_value: Vec, + }, + SLoad { + address: H160, + index: H256, + value: H256, + }, + SStore { + address: H160, + index: H256, + value: H256, + }, +} + +#[cfg(feature = "evm-tracing")] +impl RuntimeEvent { + pub fn from_evm_event<'a>(i: evm_runtime::tracing::Event<'a>, filter: StepEventFilter) -> Self { + match i { + evm_runtime::tracing::Event::Step { + context, + opcode, + position, + stack, + memory, + } => Self::Step { + context: context.clone().into(), + opcode: opcodes_string(opcode), + position: match position { + Ok(position) => Ok(*position as u64), + Err(e) => Err(e.clone()), + }, + stack: if filter.enable_stack { + Some(stack.into()) + } else { + None + }, + memory: if filter.enable_memory { + Some(memory.into()) + } else { + None + }, + }, + evm_runtime::tracing::Event::StepResult { + result, + return_value, + } => Self::StepResult { + result: match result { + Ok(_) => Ok(()), + Err(capture) => match capture { + evm::Capture::Exit(e) => Err(Capture::Exit(e.clone())), + evm::Capture::Trap(t) => Err(Capture::Trap(opcodes_string(*t))), + }, + }, + return_value: return_value.to_vec(), + }, + evm_runtime::tracing::Event::SLoad { + address, + index, + value, + } => Self::SLoad { + address, + index, + value, + }, + evm_runtime::tracing::Event::SStore { + address, + index, + value, + } => Self::SStore { + address, + index, + value, + }, + } + } +} diff --git a/tracing/3100/shared/runtime/evm_tracer/Cargo.toml b/tracing/3100/shared/runtime/evm_tracer/Cargo.toml new file mode 100644 index 00000000..1b724f04 --- /dev/null +++ b/tracing/3100/shared/runtime/evm_tracer/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "moonbeam-evm-tracer" +authors = [ "PureStake" ] +edition = "2018" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +repository = "https://github.com/PureStake/moonbeam/" +version = "0.1.0" + +[dependencies] +# In those shared code the branch is irrelevant as long as revers to a rust2018 workspace. +# Each version of the runtime will patch the Subtrate and Frontier dependencies to the correct +# git repo and branch. Since cargo don't want to patch with the same repo url, we use a dummy fork +# not used in the runtimes. + +# Moonbeam +evm-tracing-events = { workspace = true, features = [ "evm-tracing" ] } +moonbeam-primitives-ext = { workspace = true } + +# Substrate +parity-scale-codec = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +ethereum-types = { workspace = true } +evm = { workspace = true, features = [ "with-codec" ] } +evm-gasometer = { workspace = true } +evm-runtime = { workspace = true } +fp-evm = { workspace = true } +pallet-evm = { workspace = true } + +[features] +default = [ "std" ] +std = [ + "parity-scale-codec/std", + "ethereum-types/std", + "evm-gasometer/std", + "evm-runtime/std", + "evm-tracing-events/std", + "evm/std", + "evm/with-serde", + "fp-evm/std", + "moonbeam-primitives-ext/std", + "pallet-evm/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/tracing/3100/shared/runtime/evm_tracer/src/lib.rs b/tracing/3100/shared/runtime/evm_tracer/src/lib.rs new file mode 100644 index 00000000..5d998775 --- /dev/null +++ b/tracing/3100/shared/runtime/evm_tracer/src/lib.rs @@ -0,0 +1,117 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Substrate EVM tracing. +//! +//! The purpose of this crate is enable tracing the EVM opcode execution and will be used by +//! both Dapp developers - to get a granular view on their transactions - and indexers to access +//! the EVM callstack (internal transactions). +//! +//! Proxies EVM messages to the host functions. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod tracer { + use evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter}; + use parity_scale_codec::Encode; + + use evm::tracing::{using as evm_using, EventListener as EvmListener}; + use evm_gasometer::tracing::{using as gasometer_using, EventListener as GasometerListener}; + use evm_runtime::tracing::{using as runtime_using, EventListener as RuntimeListener}; + use sp_std::{cell::RefCell, rc::Rc}; + + struct ListenerProxy(pub Rc>); + impl GasometerListener for ListenerProxy { + fn event(&mut self, event: evm_gasometer::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + impl RuntimeListener for ListenerProxy { + fn event(&mut self, event: evm_runtime::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + impl EvmListener for ListenerProxy { + fn event(&mut self, event: evm::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + pub struct EvmTracer { + step_event_filter: StepEventFilter, + } + + impl EvmTracer { + pub fn new() -> Self { + Self { + step_event_filter: moonbeam_primitives_ext::moonbeam_ext::step_event_filter(), + } + } + + /// Setup event listeners and execute provided closure. + /// + /// Consume the tracer and return it alongside the return value of + /// the closure. + pub fn trace R>(self, f: F) { + let wrapped = Rc::new(RefCell::new(self)); + + let mut gasometer = ListenerProxy(Rc::clone(&wrapped)); + let mut runtime = ListenerProxy(Rc::clone(&wrapped)); + let mut evm = ListenerProxy(Rc::clone(&wrapped)); + + // Each line wraps the previous `f` into a `using` call. + // Listening to new events results in adding one new line. + // Order is irrelevant when registering listeners. + let f = || runtime_using(&mut runtime, f); + let f = || gasometer_using(&mut gasometer, f); + let f = || evm_using(&mut evm, f); + f(); + } + + pub fn emit_new() { + moonbeam_primitives_ext::moonbeam_ext::call_list_new(); + } + } + + impl EvmListener for EvmTracer { + /// Proxies `evm::tracing::Event` to the host. + fn event(&mut self, event: evm::tracing::Event) { + let event: EvmEvent = event.into(); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::evm_event(message); + } + } + + impl GasometerListener for EvmTracer { + /// Proxies `evm_gasometer::tracing::Event` to the host. + fn event(&mut self, event: evm_gasometer::tracing::Event) { + let event: GasometerEvent = event.into(); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::gasometer_event(message); + } + } + + impl RuntimeListener for EvmTracer { + /// Proxies `evm_runtime::tracing::Event` to the host. + fn event(&mut self, event: evm_runtime::tracing::Event) { + let event = RuntimeEvent::from_evm_event(event, self.step_event_filter); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::runtime_event(message); + } + } +} diff --git a/wasm/moonbase-runtime-3100-substitute-tracing.wasm b/wasm/moonbase-runtime-3100-substitute-tracing.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b17d1b58a3ee486e75b8589b84e42193af03aaf1 GIT binary patch literal 2209177 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 z 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

Gi1V?XU9AR(FHs)dg(F6p?qG?>P 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

a>(;eK^=sxqo<-MN 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 P!_Zd?K>C`$jq~aJ5ueU6wxq+ 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 z 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‚ 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 xS%;oC+TFG(% z=9eRD4x$#RpVylj;VAfNiYBmK#$242CoM1kDv&Li$3{Wzfr-AYt>CW83IX3R-B)UP z2ZvP%Uxsb(<~7HQ>K>9WdKacVdqpbTUvGr% zS~;$7$k!uFv_IR;v7$$fcaYg5fg&y5NS?EZgVMU(t9rRf6{>QQaSc%bZbmj;!xN6f z?wW}6N8rAT#U`9=>OXCdf(y|h_T(_3CnFsjOp>PsW2f)B(&cF|E{Jv_Xuq-EPryi^ zTa9-k92eAnY4s$;(`VoTE8M4SwG2|}=sp;o^CT;AF;-~Emh94uf${1UGACG&if@f{ z_c!Ud+2VLg4fLYmGEnDXm8b~g6KO!Y&q9|Y=qbOxP)zxpd{>cUG*F;1S>GYqVVqi^If|W#vD!k1emNzntPlyGp&$3WTo`C)|`~!}O zVed_vi|Kasf?0%LG16h;bDG z9M%N!OGwS>xPVbqlGD%Ft->12se5p*sC+6uY>QTtm>cMCsBEuUM-S7khYYBg=?Kv> z9A4VZBdk%R$(8>yPRl~Ewg;9Q59B)=ZFSv~_jCt2y02N_lee|7@PR(e2~VJRO4Uh0 z-WXFCFAq|mLD7CMfS|Rqhc;{&(7tZG%QPIcw8&{-7sB?4cmLJoN7(_gF9%tO#p#kV zR79tUCVR=&M_?>%G8rV&Y6dcVud|{Sbk+@OxQQShE`ne^ko$5Cg_FOpJ*kvkaKnXY zpgobocTw18D+9_SdO98=`g8zvBVji(f2k6()yaP-oVRpLgS}C{c;O@%t@dZ8%#p_2 zm;~cMTC^_3y^aVc)C4bjz6sGzKS=1ZXo0=yJEPZowlVHY_bo>6Td*+>8O~vybo&Cl zCPqijylyxFQX&spuU0sJ4R!5nF&RLU+T(?DX2S}lXp2u%0AWu?&cwE17`9$3!B5&N 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�z$gtSs*3F)2|anyX>`m|5t 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

4bBnPk$ktrS&7zVud<(6W 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

jMw`H?}e!I$Q>V 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

P5-xp)lfEA_kR6n}AtEi9)z$Ni$T%{x*NFIKa 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 t&fbecBL&Vji|xHa9)c{iNfn~Zw^yW(I)v;% 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≶n)RnF?9LCJ()omaX7X-;=0JIBrXfn;=;PzNO8Z5m9P*}h+SP>W={+i2D-om ztE>!1TDUW`2>*TzSHU4Y8q)NF0Z>rei`T1O3u4p3r^?*_|NoC;VvI4y_(6ymV~jE8 zQ0F~m6=WO^*1iWIuz5J19&#+jY@gDm#x!p{1P}m6E4S6I0ty6$03kxe&}qU1<~1NG zWEEto=i&A6j2OXx5&){9C48zDFhOMIaIk!;Qluy?4i*m9t`&0}tepS<|Nk?VAc6@d zz!XqW0mj((^t6rKeT8hb{>;`+$lHk|a~AhJ^{4W>ZSK)fa6BOt+|GvbR6ii$gxLm= zI$VeE@-wZ^IFSFp<%y*ZTnhjYHv|me!{&==b$X`N>6x`>A1K>L%H|?Mbl@VeX+t~9 zjWcsKv?L!X1(aX3{(!WrRtLP1*Pqv(Mjqz6a(_U|IILw_n_2r|+D+pARG^)CLdxD+ zno%V%er+FvVf_F9rk=rCYybcMe?M!jeJ|nvcG{1v4qB{j#$e+=S-0%pW^8rFVE=D~ zw7;IH60a}Dx_oRqsbAY8taAWZQUNQ1- zihDVD1*JB#_r`EM8&_;G)~8Kvme;*8B)u^tC$8Q1tm#jX&5WbOJu*7V8j^6S!#wK2 z;)@VcL-;kX+1JmJu+8h8nFr}+oLiG5_V^lC*7(9=ru{<^gXWyXt2ANVK)XYV4{AMDENgwuF%$Zp2P|0!4{_@m9EX*a$sxvX#$|-C7XbsVmAR*SVj84Jo$Mo8)H%c>BG8$P7c%hBeX?O z-+E$Fnv09;4>%+{iai)FA?5I?AtZ4zkt|h%qYuP%M0m!3U3Z<>rgFn>|W zn1k&QUczd5rdhSRH3_5-A^esJhwQ_l4+YmII!ti?Mz{104{l%sb2HG#Zh-_hnTu&MCum5(BDH!o zvPfO%LviKSPRR7+>04n9;j~q)=PlI-eF(J+(qqxdwLu@A&_j5G2njU0ECqciO_mBS z05D(-L*2|vsDB$lA52B1B&JXnk;S2bKJfGv2iZ)rrs4oOi}h69f%NkcoNA>9L;#=< z*&pfwDHwmI{qsS|zVt**TyRVU8aq>NbC6IGU0bMnpo&^E5QCbheFCM|G(8aS`G?I3 z*6tH9;K3Y7oSM+?E-j9o%=00Woe&qTC`zQM6FeVUfn5HFBPPV*;g@rJgcrhY>~B0I zPYQ4BXH4s5gQ7G3%Ec4^XTerxYR@}?yfyj5l}re|4I~{17IO5<>Xh}0Q)H-9v4d6z zZ`40mizEUwqgPN%at{uM@c%pzigkNY`!lw#8w^70`x1l9HV??cjc@K|euehI@;(P| z90@GAJMye={t&;f~=mE!pC3i#V^Bg;H#BYpA zVgq?pa-G4L=7c6*z=3MVfg)`U8`8i&CsuS)D`n}xKwtyWL<7r1d6%{M+lE6;n7^U_ zH89X8R#?3`xP4O_*!SztAOM?L6?yK*`@7R?AhhFpr1~fm6`+kh3j}gLl?WwBxq-(4 z(yHsfkw}M>QUi_*^m+PEOm#!PJc$d|qoQE3Yt9+AeOrd`gztESw&S8Jt{gHvk<=a%DWXM3S-t5+zCs?N5^w9dHEr#la z3>CiFh!v`dPm2PbIk7vcq>~0*;|<S7!4`kS$tj>;@Uw~_~w5f>`C~wz*WK-_yU-Gc3M`6+^e1`Da+u}}Ec|{#&1o$D z!5I+G-cc0d63M+jc5ZU;QhdRfpRR53?R^Yvb_igEEtGD*dmE^$k?vWhauZ~=@MePO zFT?p1=o@g*R&)6zmF$gTO7V12hL8e@Mh~(LX04x8eXN__%59D~b;f9 zpIN-|%7dkTiDoQU@}NO`Eh8cIgT+gtP@!NdDnmteswC;|j<4;e;Njtgw%lOaRpFb1 z!zQ^!Xr>>UVzP=C&W>%@;)Mi|HCh3`PQL>JmrDC|Y&Y6M8!v$9BOC_~6S*;$l{sD* zf7WV(%yD+deT&eDkt@>&SH-t=qnn81qSh>WY(e_DtB0Z2@|#|W$4D*7ikc^Ig}!6u zLW(up@K1|V^JOhcW?S{-k4ICVE#8#Uj4~aYGjLm3ZJX2hxegrz?&vcV_fF~#Z6nL| zE^t;);*}ibSoQZN;o|E1r)t2-@JpZDbrP!kZ&NO=2C$v+=)@&&;Q&00{WSP-8vX%X zV%Y&ro?P-%{(LwMpErC!RB z%G!o0n1%2lcVq(IljTQRDB}-9(j9j9mth4Y0{qcGaaiG*F>Q+@F(;B&fEnw9FS%}2 zhz~2s%^#mhSsV&iH{hzK^=vd)t z9R;J`5Hxg8K|Gx*3K&zNrh7UmfL&;fN~wX7A-AfRwpCjM)ctooRJC~T6pla?kQ~)_ zOzr-$dlML(d=lE|B7IDy62Stmb5p^x6AWXN3cf``*K;5JACAT~)69)87;~?En=da* zLvuq&IZb4bnHbYtW1ADs*K3d{F ztSKwT>1`;+5R7W;KM}V0M)AMP5|ehhv2wk96yba zY|+`M-N9tucB<4YE#0)UEI)0&)1F_ii%l4X4S+;+yxTN$l)WX;ZJ(e(sjQ6gQh!vl z+Gm)6d&zRTSS1RuKvG#wAFFa&>kUo@aCA{cC6H_mY(nebVLE9|x4|og-qGJE6Usjg zDYufVC{X68iVkv0FSk-kNFpzk2i3VfeR$l{B#wd*=6lJBr!h`Hfg11yBJ52DGE8wV zQ}rOy%4zCc6!i%w0Yn-lC8@3j!{iLmQr1bjN^=({18SvJ5BN>gewblXgRoH9*a0qI zSMG4HHWXj>YP>wKtQHV1qtaOGwn0|GWq2>8hu35Mdy4RR9H62$AkBR z-{??J38Z;?RwPun@700dKiuXvb7c%5DgjWhk?UObn=gV^bwJHvM7D8 z`$jSm;x@>z_PRrFl`AUfl5G>=Hjlas#M}Vw&7q7xo#0I}Y*YrcQI#!g|KAt4ZK#>U zsKv71T2(Vx&%D|(PHD<4IR|3uj|KUA=wUqD2bF^B?leUCvLn2$y>O~@qCKE{Kd)W7-;9eL#!DzUcYGve^ zAsYQSQuwvC)10yw4J?`zWDR1nxu6ZFI4`j=MrX9h|sI@x4aPeda^C2^6D z{{7^^5J|n@oh;g5k)Dt*ojVxfU4UDM7*G?l!pb$|+EfS!xl9G`c-9z;* znb~GE|08_5y(4CEoL@{MRSfUd-$%yzR&@LJ(Q$mGw3cD^)6km~WFRUl6wgCPLZwWw z*dIedj78B*I)qv+t?eRI0oDke7D&q#D?zsl(N9CF_!AHP{B(l0sFLD$w3)jjS!g$? z6iYSOe%o^n*q?rgz#ZFl=Ps`@WF40rQ0WLL+678cGzZpG7I^!}z0z@sJUhAO?npZlvNQzIQlMs%biP-AmXtZ`*32l2%Pek7 z;CCHP6toJJJg$^`8ErL}=n6;6@!p^hEVRQ}KyKzxztHRt-f7tVrI-1z0kJ}%;qJG^ zggE5T-s^5$g{*>N)EbALkn*6Q$m&1T9rV<@{TzUWs2>#B6e#MB*>Di&Az#R)(VU0~ zbaGvw?-dJ;-t9f5Jo)dUBe*mGV`U{I*!m^iesul8asV{xY*$%Qg4UO4z*ljx|5mEx z0A$FJQUj(q6^S^Sj$#-6y8(|7>U+UzQT_l6LDlR9#Z)yY(+s7!{dGw*jm(62C2yq2 zp&(bAC%`jpjB80l4e&67qe^zP!d5#|ov#3mM^!@}9|VOgi6NlN4C7)-Q+A;ds2(&F z=qR3Q?>f5Uk5agD7DD|%2~bH>w}nh1S|0?}sdPC^Zv#u2B5cu)dJBmbdZlU{ zxuw^_$F{U`Don`HnJG;2-ywn$(5c&CbO$fpCs_R)e)%D(2o%Z_4ENU^y zius}E$(yN5+CKy#Cmn;jRY6@#y_KfdDhLq;XXODqWWrWh4b3F?_*y;iLP0vHi+ zrSUNNOOj;btu~!Sv8M(#S9;-6`*H2nHDdkQXp2lSL}kY}uBzgJ+3n^qWRpQ{YvvN2>I{922B9&SIFsjdlXUBW98WF;2bmb012m8 z`~N@Ah)yNVo>g-u%5ulb5U($l=&Y8 zhttkv;2r3}E3vV8J49^2G9F5xdXloMs&BW-n;CMpfvvd-3Q`CSYT=6`a%;U~`vh$I z?bl9vTw=n+eLLb%IRpLdpHYCp?BCPA@gLR7Nl!)I&GZ{0Jw~#Nf5}Vpj6upnZB`ezNV&8ydXwrRWGrCWcV+S@Gz~TjN zso!<0r7)^I&-K_hkbE5K+03gmoR>0k!LN!$^Na}5X;qc9%*ZRhko?g#A_4Ix!3ibu z?kr+K+2jkvC_x{V685 zB{xNV-MZNQDbWOdZrTfY{}Q@v?p*8>+*+R8P_?NJZ!kR1O2VVxKAJsV;#ZLk)FC%a z0}XwMSi~>}^A&qf#RO%L7-=-4WXdFNAn9jR4>9lF01cjf{2Pmvgp2g$!~lz5^@if6 z!lK)?RhPa}>G4S45v!f%IW9H|jdI5uZv6I7>EVont9kRlies*{C-Shv|Iho|{wM$> zl=cjH=~K=PS{c?^*=93zAd9PXbiP zUeKBCMDm=)12=`tq>Xa8YXnlXBCx>Cx#{-o3hhRp>4t;MJT*RGu(MG^4#>qa%qzKZ zwi-|Sn%T4CG2u}@S~dkA1eDcXXo|*zd0o}fE49Ra^9roXc~zVr3bJ_Ro>3G?4r_GPx53o^eCt>ENO}HoAyz=C&^$<8xB7kD z?pcOIwfyLINYHD!0m~WQFV0C&F)xvT>lBE@XRTOp- zP6k9p%Q25dG#E)fTPqAiGm_m_xoR+lG4)qmcNao-4q+YD=n-aQk zB8`=d*h{_9l@cgB(umARyXg`?=d}PpIVUcob^7{Q)>{~JxeT07jO)0$i0|CZ$Lp>LBcLzFTlbyNKi2hldjwf0Zr0Oe& z@xg?d!mI6t!lj<4J9c-pC()h);LT?aB+^(iDOk?c^cGDs_lVAN+f5u&T zom$hNzClc&x8xt*@2?g1w7F(s{wvnX11~Z&0gYw6ZjMSi5gYi#QrNqpFp*DNeeE-i zvP%!4pIi%ts#SgAi0j}nGD8oCpDq!HV{2{>fkMn?5vPhsW?4X@G@x%={`ql*tt~(b z#sglPv-Ex_6Go1U^%Lh{Ni$K&W_NLRtF=tI)g4(x>ltDXddA|!xm#MuMIUL#LKlP) zk_$`nkO%`6UlwM}FZqN87U;>I4A^+=sBv!PgW39s=918c-w1oJtn@q`*6Lg!Xt90Y z$Hjl?Egd6)IKGh8`l!yhSoDcF=RKpuR+IttqWm^uKh^5TGitli&0aTv)CQ`zB5Mc| zfO@pKNNX;EAQSs(%&A3*M`JLRe`k0PA`_RIAr1>ZpFO+~vZ6QyWBDB9ZN-*0f2a(Q zs4k|~-yMaT@`?v(b_3BTSMz^}4D4=rXm^@2oIh)u z5ihO*=E4?B*K!hlo-QO(q#+}yGty{0vA)@;(&|5x$`)hrGsU;`<_Q^AM6`g1gy;f_ z^M9e>cF5eQ|ZIL68JH8NnJr9pb6vkxGEO$i;VZt5ILf?_e=&jvQpzI1*@kEAmuE zr2(Zqd~Fim8*YeW9dsrbep%Z6>RGEq8#Gi-A ze02wHj2Cz-pAqp5{5;|qawAC2@UoJPSMB6M-*EL^gQ2_%gI2PDG$c-wNoD<*{(iW| z!gkgJVI4CLSHiyW4UWjkp~ET4NbjkYI?#rY+7tMJTQeSf@%4&<1L953=z;rMZPBz2 zJj!hj|3X^JC;kjT=ll#Jzkk;LM2BP7YJ| zDX4-AanpOANFr?#=cY+klO_<^9bf-)QMCUIu%0L5p!a&?qEMT6?fS_0_#6h~(W&^UEKs zB$3kgZsBOog-+&f)y|bF6ptYF!!MV4kH<&x&@Nv{*Q*!W)YY0=dP?nA~m;-ERQW^ER+81AQ~}QeXc8DhcSH zKXvHG94{u3LkC{i48b|Q&TXJTU+l+^IxqML-I~0S?+q|g0H$8RQj<;7XypMgwAliPvCH6S1?b zh9QU#(Cl8Fjw6+ZQY$rE((R!oIhGy#mlqwkZU*(HZ#Qj0WW(`BblM@{y^9;r0Ywn8I<)>o+tcn2HW!jH6F+Q1KNsw zFFx+>pk258uC|BDlBbC@s>+_?+5yqVttl*4CRY;;))O}x<)3`6kI11BgjO!5U%H<( z6eMXN8H;56ECRMjU2KW!c3TBnbRweQA2n8#8wrdV;j6U`IEItN?0SYb-JQe5{g*&D z!34EyC+$V?n;)5&IPCluo>s}#Zh8z_m}}kjufMH|9d3pUzp`k4NV90~V^Ka@3&oF! z9U|@}A?ZT7=lP2B`uSmW3d|}=bnsn@K$37~@1slCP`HlyD5GQ^tNcBs8X>nYMR(*= zXRtP;Mo~{s>j& zP@QNE;OWXvMWo*xStSeQ*;9Jm(n6 zvv~$xgKdM6m%(n6e-YC@qJkC=-J4_aEG4mal^+QkYOuiGRz$;+xE zaRw1R#kgvgpItblZ{`48;dS%1?77Lqw~k%O|Ey;_W*W)4qL;}It}ylAhU^npfcmqayYN@y1OVHc6PP?(UFAm$yW`(NKmLCQ?Etb@fcLXg@xd#eA1*w3a zi`5%_VFQdft(*nMTfNCV%imF6DhfO&OAYtv{=fhYV6hldZ2fiO82`hGq5Rc;q7RD} zx)}yhy2PszT=o~Mb^j_3h0U#cmtguiXmmEF?{9dx`xPeO2uo8JFfKqz6SL~wJ>5ZIlX zcMbGt3?J&j{2Bx|k9Gk?j-_P=gNIE%Uk3o$Ov4q@KfhZ0u{)|FD*6P7?HUhPexNL| zu~B54cvIv3d`W6KG_ZE=a%2*$=aS3{sjUtQ#lnufP!qcg~XfDwAcb&p~EmWZag zbzGGutiM4bmBT~A)eVO?$Ieu<(2NqpBbmh@a@z0%UarQ@zm2wei3|0!%|u&sh7sz7 zY?WgRs$AYs8Y*SmjWvp+640F9O;&KE22}B4=Eq}h`dx0^o$<+qIG>e>pL}>2e{!${ z!@|04#5&NsT+Vjayze5vHzQ>i(rk1BBx?H^u7x>>~pzb|!^gAdosz z2T`(PM$-^)y3XnSI1TAp8w@&qMRic7=c6d-JR~qaT%EHxtwHCQ1%aGOs=9On3Q9&% zL33N%<$k^S@}*m>nwzH%KeD}nJ=7pkfPF#Ow#nXdZz+?M0f`6>2pb5ctvvpw(k%|J zIUh0GnpH;=e$sJ8-`A1DH$WXZeRWt7by(3?2NU}0P(oiE9ZTr@dy6q7ePk3k@xsJs zL#~T1+kTbLg(aG3+4e)y2X;b<3m!fja$TfE`o6OOg$W|IEs`QL!iRT3I}*gUPAGA) z!?v%ZioWk$=z^GRi)7`68{q^ii+0aKvQW zzoZY87AY*)EmE#L@h)gbhJKg;3T+8e3NWAoMUib^i4=sQQDPBE^r4q8}_akVQxwN%3>D!chmf=-~)2rhL%_2?>B;!3r{XfuW1dl*I~IRv>bn zKvyj*D5-me8IBejiZ*U*p&_^J*Vww#0T|l8JyW3TyUn}FfG+yJDWqoCck%;2tp@^7 zLVu4hT=2om4q1dTqW8qm7daTwu*8-dBZQJb!5B)=0167M01P3XI0<5wL(JAKcD-NC za04AQDx_wcTTV>GqKjJsi_;QHOim%F0Ca*GAW?%Bk`UP;1vT_skc9?fTp<+1$P7U6 z5X8t0`ACQ>J;Z>CE_5+}%e%1p<%p6NUU;cN5({Gfw#a5zoe|j(ILTW{n9Ke!lD9r^ z9KY`-IqYlleXj)1wtLL@L#?&`$FFB*W@aA0s={U{6bkj&+Nk71i zcOl;S3q*pIp5#al3$Y01)3-5_zibYPnux)>tW;q#W|-u-FbPN0ME-g)QfjMC0b@4a z6+fH;3RMl?g5pPwzmB0oP}mXJtq{WgY%yKi^D|2{4|Pi5Z5 zavKfPp&*BSx>J~rVS3XLv_rR*dlzPhfG+HN;$~=?AM8r>GW~%HVb5gNSngfehYLR( z15#a+ce}>EH194fT&g!rccPO0eYy9i3(Ym}Qd{52M0boP>N4dXO_J|H^ZRSkl&IE> zr#WNzuDV$bz?~BN z{#7E|a*&_j-vpu2&{VrHEGxP&5a|9~m>s(MZ&+p;Qt|Xo7oOTB+V=M*CH}qG3o^UH zSReDc;;a;uW#FL?gD}43HaJfK_*)mIt*edaf(wA2m}JcIE=$YIEQf)cM6I=gM^qSSMQ!=GQSe5yQSi3f zD0s7?)>Wk$fqtUZO+4<|~zgL^N7KTCDR?D?)gVm%cRtPQ8!UameAol$&Prw>HLIQQyh`fa6 z9tLsk!emTPXV&(;_g)j+`RP7iNCS6!N#^Iw&mBq{&AYFO`vXPs@O$E657b=~NTVv< zh2`447x!?Adr*XkA$`6Nr&viI3YR3wKrHiZt+lp?y&@?ueGay8UNUo!7XB=SI2)GW z4%FS2WBlNepT5Jc19zYdSb)UEzHf8S=VDL??)(-0gfwrNxwqS%0I%&2sn-3v|5tWt z-}il=&o`1j-`z-;mgF#uKwq@V8W?u5sZO;s4e%4ozBRs!I*Y|xj5a-_6_kAfcgiw>8d0(>YqXbZFGH{XRUYMpTEZy1nPWpTy zHbEk!lW?oG$`n7~pCKYGPCrC7nBs>mv+d)&QJC#>?*Tyg-~$QJeq>J=slp`)08pWU zNQ@;d7{ZAsZdWkcd+&HfOqC#v#=v44g31^~7>xnNXpA6{g)x}$bj+?sVUr8jO~ZEY(0MrLx7ig^|)x6Glo#7%54S zLFtK+k_uAf4@yj!&@#IkDbY4sai$R%C9v0}T4Ks}UF&L@xBWs}Y!)=mIZBU$_{3slw=s6{9ae@GxTWMTXFbFGfsLdSnYm zy)7p#Mm-n!VAR7I^@jMuhz7c)8j+EgFN}II7}+qpi4nyVG05=bh9$g6cRkdWZqTxU z&~k$mEOzjLr-Bhr3_;t{g%>6pl4uB{XOz@}Q4($R4SI>UOw}QD@4ZFf^|P4~vx$Z? zGE5a~G)MH@C{&m~l!yvZ8TA{rGwR3k0~RH+GZZ{D$R58L8DjY7g_$-dYs{%pujv3xo&6{QlI%dtY%sSc=tE@4ztg+I3BC-Ex zJ&=Fa=VzHigt7^weA66K{*ZcGS%_-eEPnc%B`YU0g*Ls+gP%>4jk&Y63)3;pFsvcN zM71_e70ax*W#(Fzu{0$*nnKQA6)Q>x0{ zDRn=_#PPF(EHujw(J+Hs49ANY_&De5k6-gMWzEh$j=79^b*(5FEl=FGja{`o@w2ZT z|A}mq5YwY)E^WS&-*;uOIK(%VsEx8k(UxeXiy@Z^Rgj0lQ(^|AvIN6fV7Vgm~?_b0eqB>;ap<;wImo=A*Uu1w}i1lF4mg!Sf| z-ZX~@nM@!#U&9=(nr!72LXe^_7sVodx?`iM1@ zs$hW$l_J16L5)I&FhDf85@dsv9I69Lt|15_mK=#8iz?QN3t*IBp#rqz0rpA*@)pey z{1j^{kGsXaD;B*PPT(YW1q>UAuwdv5FjE}SU@KDpx5ZtUO%Yc#`9g~WXOP2*AT%qsQBQUzLG!0&qQ`Mfsc27=Iw_!s+yV(RG{rf?a(*lQ9UE#D`G5S zk<(PbOu`gg08Hf3*2hshzhe z>mF%*WPE62OZ;94`Vu=dbVol8xsWJTpi^F6xJqTAu-84IU zoY7{oBR{SEoN^_KH*JT?mH7WeVmReWG*=?ve9i;G`J5L&#~dOgnm}^?%^~II{E&Z~ zClb>!LWf_L_E|gVai-i+dB)c%S*4ayZPX5-U{(+Q+_`Ock=Y7M*hGVj)o1c+KeKN; z!$w$+wyjpktj#%WM&eMg?OUC{{s_yqZ+ATVrji6IW=TDN<=Fy!=l|h5n_xc-wN|PA z&y&dh%pIvzqjqScHQn|t3MTC&6GU)fthXPUa7EFGl8xG1)na6}?b|5+vQvCkBCsCk zf#`hBgWzLMiBsbI{{(V!{>>DGfRv`yeF{1?%i2MUuOmLI{KAda^xRjsYke{2QPswI zSAB&qz6Z6wz8C+4`l>Jd;vb;C?u)N0>|gw^Fr61atT5J#Un{J9F}HCSR-=$YC5^!f zHH6_q%#Hv|3|>&6v;r6+V)pIOg`M!l3Ra4Cc)zC#0 zl>f2H9GtS=76Y;jB(icFV8EDB#MZ{dAQ3{Swrb2cssKq3c@$+-s=BH$@If;Oja`}s zaoBl*`0Jkb=_cIt3sERV@I6{n6HF0=u>vZDxM;x;S9}q(k4qbxaA6rpuepIO3kewz z0%QbL79b;#P(p@c47c6aBEbZM+cad;lQmTyJQeNPj5`#PQQ4hJtQ5NI$u`!LGtH zFvb|;EHzi8xiap(_ueeFMDNd@T_qQY=E|<@+@S7o2FJ;kj>M&h+U+*5f#jif6%}2W z6JgQK;BYo-5Z#?~GC5AR^dQ%!*O0XPjq<~V;g|b}b~nfoUJcUcez+r1>=a96vDhs3 zsGfE2+}MGn{p^{6MnBw-5y_fxCoFDp{vrZ#e0Ct|FZU7o>EDy;>b8gJ!cOl1>ovLn zQZ#C1BKbphYYwfs8ar8s1>Su4y0$eY#(qZ*vof;guONTn-{CL3^Ce|f=52Z7%(z^X zp`ejPY=6?0r8vS_Act-^Ea!8Bz;682VIH%wT5&t}4ewW!lo64Hl_!|gR>i>yl-qUk zRz>g_SyO?wOJZook+qz2Rpzo?hxY!JYi206e3BNFVUa!;+(6%G zp2jTg&gyQ92qSJtADdC{H$Tf6q>P-ACs23+D{zpx_nx=%*rCEmp=x^0vm|z=g#2N9 zCV!|ce^Q9;mB;@Dbqg*~wtot>H?VcT#~5Rbt^F)`?X7h|{2074Qg%=FL?dM~k|u-n zu_xJup{~VtioLb2z1CW5?X@9&>>bCM4l^H6V@gB%$Zor&%stBXca-kxNEwXgK^l{+ z(a?}Vq>ZeRHFAbSJ!e0)RZqYhwK|$3M+&+@WR0w0uVHe3WRR^^v&~eft-6Aqh)wAvs zDhfH|Q*PUxR{QR~_kx=Ax!}F`T5CA~K@bFMNI1X2?DZR2yRZ^KvIYtZBE<+R8-y~2 z3K!qK*9j(5Ac27^Y)m!?WeSxoHrN8dkR)!hD~9~AgtXg4{`#yAXLZ-3+>3(@q23LG zUp4P^;kJ8xn%i3e7;=m4SkqLS1+OoA}KUG`y zrBmO2tvGDOH+=t)#=3)IpDlT>2gPWQ4AF4)!cGCGu#6{CLHo|Hw^qKTUtG-_=>)YpYlU!V{bHrgJZ%jIm3>s4(3A9UFM zAPzNbe;a19y@d1HY&O*0-QDG--t!SOowmhkl}8b^$4#>Ri0xln*#4;dus!wkwr0>Z zhTfg)pi$3VsW1;}3w;0f0&2@Y=TvMd#Hg;r14$B*H$rICVo|bR;Ha<7c6To$BV)Rr zvpwqe_a?T#g+PtnU5)85(Ws|ssu~}Bn(=8!Ag3SAAvGy>0?81-vAlP8cO&V;bNA+Q zIq*xxfNy~cs}}*cYJpZ6grQXAJ}R?slDGV3QCt2?wkw%!-|bx2wf*i=HuR!CzEAu{ z>0kqL88W&B>BJ)>;`lvZTh-wVh1=O7HoZ-c|;)C;92U z)O#$>cu7}$4znR(O&F(a#ySAJbT${I`!aR(ehf!f}yPo=kp6Wmy7=}kXoou>)bU%RjxbDPF``<3ONDSoE-(LYwC=u-f!=p19+ zL33>n8DfH(Ye5z>-vpHlEvS$ZWBm{uFJePXfWyR0Q^*4|UcU)+ki=M~(2Te7=)U@T97O7IvBRqb8J1gPBHXz}`&i6Or|K`6EUA=x*Ii!Q< z;M=J@#{a(R3(NU0%rPyR%c4zh^E2DlT!x8;rWZ|A@7(nDo;l%J1NAedkaK^J;y_5F zcISa}a{%=;50)M{w~%w=d|9r(H^0WdTz%$B1RBr!3GBSN^Q@gu;h)CWn2aTK2dVC$ z6e6F4atMvL@gvQDri?Lvc*p);MlmNngQBUCaXp1osp~d%RVuG4k!-+>88{dR=eotI zkzr$_I;B#o88<7uT3xrRn;XWugT89pe+(;5QmW^dq`q*^PtRSL4o=LFzieNSzh*9M zCWNy2XkQMs2mW-}70M_3QtJZL#fP)l^`mVnps27<2K$nzEw7KMRM_{mpq~CHp0exX zBI--#YiPcH=SDZ!^=s4~;?CmmDz0XH{okoPPL4&qYd{?(F6NUGP!P5pnxtSyMNRc{ zOVu`lqy`k7{Bin18JUv~%|?|@bp9&k%*jmW zkAyMStA*|VN>XvSDmI%PamD^wUy`~gZLd`xFQ1iTI!pAumAE~`gWE6AGpHSwPF9a9 zo&0CbDrc-e62@k;BOjyjM_e)U%M;64bV`9bbuA{XpH{7fd<0%e_}bMIEzj!r>@1M_0!U!RSQqu6`k(X ziKgz!rG&3}IG_;_>+i|i}+ZoysV&`_|XlOxWM}xQH zWT&cO3_kQQn-{9siK<{Ek#SwQdCl@ z)M~YaPqpuDsGzNr8DB&Cd|xB8QKb`{4@)OGuk)&$9r>8h_cI~5<0Xc-^0G=QZqm>7|V=0%*{v25V|aAN@5}#!0i5 zSiKljY4f-YLAXDZ3{|9_{wNyCN^PNV7ggjaDO8W*K+o4GoedX@bunCGc&uIzuLzed z^H)z7wPy$jMZ2(`AW&9pDBOkh! z5u*(P#{B23@80XQSb1 zhouu76DK7VL9xk#=pmFTQ>R;wTc+%}RUTXA@tz{;(C+D>_T*55HV;Y`RLG$C`LD>8 zx_Y zMv0Sb4-v`Yz&(G7JjY7)CCZ?lo^jIl|71y2mX1e+LwV=LCN8mU==Ez|)-e26= z9x+*LjBcl+g!Ex^xY7$-<&-@(We-x1jIu|EWP9{vQE`YeIO6%Mhl+akXtDisP1*C) zL#sUAlS6Ge(DwJ97;4LVlblgjpwG0`t#`_GuDDhO2X9=5+0Q){|X zoGW!DWwAY6VpNxx%Htc2$s%L+)D$p-Ms;YZNvk|DJRK$8+E&MrzL6+HP&%iOmJJ#3{O&yw_w_NRU zgVT%>%Ve=z&RE^-uyiux^9(b*E&JoYj=p7TkN-M4I-kyujuIBgbGl{C9szK=rFhG5 zizOCqY*;;3kJVeH7p8rcz6=>Pq|Yi{rQj;9JnFtNG&Cp_YDS-Ql#o6;G}0%AS45*O z9htw-7~b|YspqdHf1yI|(Eeh0AFi(qekgoXru{MzQTYg3G->js%eUmk{qf@dG-+~x z{Q@qseQsDid9XnkiXhP|gjvB04nrJ12{n8WDlE+DqEM&WA;iIO$;v#q_xpQ41W`S{ zzz4yP$uwGVFcQ24K1iCV>I8-#sw!+W(P}c$%4LJ%lK_e)8fH@#3XOKuq0{zH2_SLX zajgB3#_dI+uEjx>wgzHw6i+tF6F=E(wu{}_Fm$`U1?bdE0j-7;n4cS5Ch}HHhV$Vt z1nb54ex|LwoSKCK7O1bQfy%>r&3Y|M7A!fJiENKdC09{FtsZQ@QF$E3Q(Jz+g|~g; zL-vWo+-*Kc+0FjBD8CG}I&2Dih!2`*9y1n_Bu(;%9x@)qj@+0~eiCPI7Ke;kuP~Y! zsb)^hm_VYoY7g<1U}E3egcJF3Hkxr)S9di(=~Ny+>b^H;EZfJ=xY5iej-5kPcfNjMq(prpqu}eq>Ze3iwq)dq%HegvPRlaBF;FJ7}}=px)A9W-oh{pLwgHD zn#rlq-=i51Rrp!bcchiGLasC^3+#F_) zKC9E^BDXlt_`@*7;Yru1aB7cJ&*JdUpI-*)lXaPo{M6+vxhP}FIigd~_Q+InmCEBU znmr_qW}L(BkHzAzo9#MuI((dS&KZAL`e3Wu712@ziy|;6GK0!fZ!(Uo?VAgzgpBl8 zP0cbz0{{R30009O03aw33I_$l(O{CLIV4Ly6o3nMs7`K9n~TFy4#O}A8Doqggb)A# z0RRwU5D5*{fB>p{+o za^Yc3a>v>b&@t#-sMuKb-V}A`eB`J3KG2PTB~t&7i2dgMnD?#OnVy6K6xeseMwTFH zoRbMUxUKx)$`ASXo&T}N4G(th;wqrcK`^V&T|kwk=e1G)+it&f} z#!=alIcw`G9rlOnB9MN|>>7b92(K%G;o4xQk#4A2Clv|@g0~D>A03DO`dC|4bFlHT z1L6)0u0;oy)k!QWc-h3yH;Z!eXL0T=wbfP`BtQ+pz-=1MLKe&n&TV1T+7lS3Y8WEBLJI91C)6IwDLmH z?)!o5DKurdrBy>NW)8)-R(0;bcOb-_12(9A)x3>s&v=1j$s+>`*uYzjos>j)0h{d7 z;@FxKW8D+0Q~;*WtA%XJYVCs16r0QhCK*&P2%6Mhp;QvuD2Ul|Cbn|>E}HD#gYukg zV68pO3Wr$bi#}*bta^3ykthvQIFL{bXP=8|fL|w=E$^^@D497d_3Qz=50?nTnk{B* z19_9C6SM{C&=?N_ATwh@c7|1}ZH@v7oIz%!*$4-h@5ANV(sKV_E`@P-|5X=h5-imu z1&M?QjjQIMvh`_rpt3%Nf8c@0MOQa;(W(vTuTenJL21_lyt?RiY-ssD?}xW)<<}(#E$O@u{h8g92N3XU9p$M z+8-c;GzANZF_K`Cj4{c(C^3C%I8X%IUt;+VCFw#(FO+3)Ay z&Hq<_knIINLj(GNlm3@_ANP9)KfnIF>iqvB|F#R25TJEpEuT8fVb6sP2ap4+EK7I! z*u!-3>*QlREN>aZXpd9>T7zSxm2jZZRx2@$cLtxSPhpuy-r4aR5cI#2$W5@@MGf)^ z!92}1)g#gQUjz6xlZ?Wn!OVcr8hM+Ot2CK4>Lo~cDS~T}Xss91jn8~xp9OeYK7;|d zlWbx$p0)~}5-UA*P%AJatZ#nd`Q9a#Efp&pMu1em(bFpUIdM8ES`d^Zw-(F`h z>S5y?K-!j#68>9IbK1A)CFb_ukZ`ucf%34AP&|0H3L5Z-79%%+v=3u@G2<8y%3XS- zXWy0EO$Peh-@lGJmXO3^q&ay8jEOlnEsBxyA*;=A!Ql_X-PV|4N# zf3A_Va)R5~O#2=ekX~r<38;0oZL1@%Svd%k@kNyJKZ8TaSD~1PO>G&;6pWoJ<7t;& z+Z)u58<97_Vz8sj5fowqR>F8>5{aKpL?-F{arsStQwO-F6Xp(4Z3br4!?`4k z!=X!4fROiZt7)U6q8e8~=uSpFfPT9w*Xi;vQK^zoTc$Z(0q!Mox@`Ot|L`@wG_Bs}0wGihU zV2~k0==dIPQh3zYSVaz`G+y#ZICSSSdUMFkIvKz6r zcDCn`kf|T#6r!@PC%?fBGZ4mz%Js6+3#0d4R2vM~8(Tb)8a#er&UrPRBP*u$6#TY# z!9SR?N8B1P3Qkk3bo^NJWYs~JA(L}h)`**0Jl&-v?&sOKmuvT|mpW?e{6=b(=XZPR zhlqEXK(V)(6hlB@e}tiFl%@sEDi(al1YOpLQxMMAyxze$%UTPIe+*~KX!gf+))hH# z6prUFn`+<`;M>@!M?DxG9|wN7X ztQz}>8`xOvw%krS0XS-Ux0kJ33G%Y?AD-W%>=fg#JI8WEyjv?0EnNnQ0|KJ`HDEQOIQ;A~h5EAAG1QA4Z3m&Yy93&^DK0 z>m25<;sTZC#Mik5=?@*NJo|dWHX7ORqT&98hl4sd-^d0ysN)#x_m<|IKe_0x8<145 zJQy*9)LMfO&-fyK)OZmL41R5}SQ9UvmcZ2m{ybCO6MO zo{((zm@KoG9adI!Sek~&p>n(i-_^Z6{piT5U=c5|9}7?TTOgL1B)9LLk;g`Aq9q1M1zzQ?OsCJi8%A|nP;7j&|G(*_TFSj{A#m(cMQ1!*B2l7{m z_{}uMDylr?jbzxhrMZeG>;L|N~_MRX`Tx<#dXi3$>@usFVKChy8PP#u6frH2R1Q^$tc zUImd{>z3s}X6x9`C(^+TIERLWnCnaronWHvdi&b+uVk&TYyAP8k0^sR-^yHUp zOSx5hY@sNoYkR)SxQ(>F>TZI9f#}?e5f z|L}Rz)7A?+Vgtnrs2>|TH0G_#12IRZUBXvTXFb0*Cr+6a;29On29^z>>(u$G&52TU z7B096E9WY3freBf&@>%HzzC3qM?ZD@`k6VbdM2$tq! zMn}H@&vS5iszJNn=;p+?#KQTv0Mb;M_zWklI^1NKSVeb*_TsOgXm{xAlR6u0UxN{S zJM%nu=APN3CQ^HKATmF9akp+39duh?h%G^_GbxOAlW1s0DwA+6QGa>>`mzK+&?BC; zT#cZf{w*93OmLAfOMdW%j+?WJMyLBkB9duxNne8Y=<;Sq?{1-a3i2MADOUzP+9)%7 zmtJt-kZC<58!iw~-z;?c!XwV8!Z}?3Z=iW>8zF-Qh_klJo!3zx%ngoom~o1 z6*j>#)Z|ToFBBIF{EI|%U28H5tP=)jLE7CM0J*$aMDpYStC==hALAMV^bEU@(r+=I zR6P91x&Kdd9AV3xik;A(%Sj#HeBBJIY2nGAC8%AzLmX615^LvpKep*XK4fq9Z zVrj-??&#r8hWi2OD1FgOg-aI+zoV0JIe8vYPj4xM%O=p%yS{Zd# z0V>Ydon$4Tm6r^(jy2f2Pt%i-UEo4agwlq=HE7^=)|Ihf_djC zS8hcm1dtelvm(3N37opZKm@4yA6sjb$up`c619$|Sv5?M_O&3xhUgod;z+&7sB8`} zKn@P@?C8|UK7e&0L$;Nk4km|?Q?%Ep?##}pbg zLBRSDplua88Fewp$IyaA{nY}r;N?X)S1nfit#W_#9@Q8P{EXudjmqD_4d~<58+^i{ zU-*vcBt2BtxADumjaKJ2TgPoI|F%hm!)-IC(>xC^W`Ge~+prYREe@=)%7UPkDY1~^ zqZ2*o;7V&UNbT?~fo}Nv8p@WL(0({5MF%vR1pAZPm;qe5FF;iT0MkhpjZwm(nJETa zgF4L1x{*vTqk)=R#)y|As}n)d^WqYO<&b4HM~c>BzC!Ekh_pGnqFMi;ZR+F&mUrja zc_V1)2EqU^C73fy8E$%lhoKU|dTZ0f_)9yr9$j#Gk1mxq_t0Ms@yKC;pPDHoS2aV8 z5VA_e6^g%XSKPdAwdV*Anip{l;Ifgq8S&4eAsE#jtsV%@g5;PtSa6g8YQ{@U->!iy zuve2E3}$uwdQ7=q91BY(w}oG*1YM_zY_O*R+e7LJ0mVL-czE*@)SAY zZeD+0UpY%zSBwWMF2~K+%t5@=#~Dodu;!x{WU z#)$m>ri}G|j%`TVr0og) zL0e|iB;$ss2e}km%wW`=SV6)#)vzDHM9JWc%fC!sTLb;G;C!Z%IkK$XYWUe<910V4 zXYs8w+S(EZEKeG%y+9t7DN-8Gh6@P+`@?wNz??~aB69#*c^j?DIckc&;|?`(Z(XEVd7`R>WZd_ZDbEg0_V0_7H{9^?3?$*X@~I40yBcvUA@{qu@g0a;G0 zQ-cOXQbK&&>GIV865wq%%V>-+Vk(xfDCVnOTH-ver~)H^K4$1kmhiCaSnp81c5(h>bjM! zG(I%J)k7%xo=88+rE9kf!n%Ayp4V$~)!sw5yGI(lOJs4WExA3+7$6vRh4Wu8qrt7k zY6ForLG&`uO1)ky!itL-=b|JfJNcz1%iCM00ere&ES&P_Tr6gTF>oWsJ`jn7X!tTifa{3ISWbG4WAW92}Nl8t+kj zOWBK?$QVb4wBp6n!-Ck0d&DdIlg4N8gDbulEe@#8*nWm$Z~w$f#n-?Ve6tqq-FU48 z;G(|=MFyo2cper(FpTf@*=wHG_3?u1$WAfra@E?lanf5?^Qv4y>rFtDt90`kGVrgE zygtAu(&PZG5G1HuZGa4~?G%@SzIR;C6n z-5q6&gUc{rtv&PtO__i4?Jt}2uWOb&u-07BI>DMWoqXrWX5BoyNW{+HWzfb%mpQei z5E?`!*{9mTnz-C#fkPWQ2ttz+h^?r717-e52D$P9M;hNR^mh7z_I+>gaIHjw-9vrd z$yzLCdRDTB`O0MpVgc$oL9{Lkx}iR;lt+uaUuB*p(qyodjLnf|4-;uS<-7svTckMo znZzzYo4DOfrPR;sxhqkzx9Z(y+kp)n=L~_ASxjzNhhbnT<^C}Un04)m888V3F&0sY za3Ee+mkZpD`9Hy)K#M12r?n-Z8NXnHd@UqEV1rclUEw7DDDmaBf_ydyC3eyhnxzIG z;c)M9|J#%-CXJTa{Q7@Sq+?VK=A6q%k0W>tsi}j++YmC5Zc_P-E%l#KtHqkWfs-zG z5d5WxmE*?R>51NrlqPK23v!cP4|&oI^SAw{TKEy$8rWDz70+&Y$pi$6#!|kClWZ8L zcXbDIi2`ar`EK2BlDZ2X3mx$FKAO+53QewccB61Ourmo+-+Cz zx%o|&N5zV;T%%IPy(2{Q2wI63>bkS!%uzmy982$Tr4la;A2>qc5@`-%{`?j(54%+>fqEjx{t3cm>7e}+Nnv>+ z058TXhd0}MQ^~~;>x*JuOIJWG{=Y}?@K$rXHp*Y@Iq>8SMg3_ba{1ydbNZiAEN8v4 zP+_m|q;q@2+9zDu{Z}mN2@k2|2f)B`CHAPg>CNNwnSV204p%`71ku75h^1y5X^1KO z(($6ZSfs4>a7z|W3Qam|R6WE(+gUc9l895*vNHi2wTN?3_iX8%R&<#hL1bF8`{*Q| zD6oim87HJoiwbQ_&=8*!P+c={b2A%k;3Hcp*JHL?;ulT=X!W2q09)5*akKDcr!>ww zOxP9!arT7OiT8;oynzF4o`(n8PB3;q`nSZC7ZR4jMucpO!Qm+&tt1jb`s1vu5*BgX z#|CiQE^SxrFRdu1PeJCf+w{4qVC^o8B6%_T32uHhzwh8>n_sHGdpO_{zHWt2UxRTr zl9^#<5Xpa$?j}`PYi1I@R_q%!2pRdfPCYV;HJn!BOTl06i-su}JIot9IJ5$39#R^K zT3jBwhVp@eCotp9-eUXX$Va?2cl)ZHckb;YN#>y)mmTq-q^*YOUdhUligob&eW_f^ zUl+Y51D?R7Tr1!M6j67Szc;eQt&7>9hJGKQyP^yB61)`uS9ncr8z z7xc3)9tR~eDszlqG*AFs(0bxD^EZ~SLgoGug>G7C*0-RI)UuWN&n|Niak()J{KU(M+gcyxbm|*lkR+A@hISAgb1`eP$scPM2F&S+d zz1?Vkqa3%}UgOgA*)ZNZNQ)BLTwrP67WQAbR-7KzEU93Hk)z$>tS$W8mfuD^f|=fY7cJ6T=li zsnb97D53`PiY@+V7s{l7b<>OOK%l)GG4DtpWh-S<&;Ava+YFA8d$;pSSe1t%w?Jj$i;M+_&NuaopMZVfX<=f5fcTRF|KELqZV_< z23I=*lpLyalZv5}AjHh0RFKs@7^WL(!;?;y*1|^`TbP^L;2zmEt?U6$Fi+jLUHpLEF(8>c@GsZgzOAMBkpyj&eNZu{~^Nnzg)U(25U- z+S~f)K^;^%5%sLrfAGcE`fHqPz(3``NlA7V0AXQC=>As6RJW4+L}?~^5_*Vn^YcX9 z?O3GsN(fLtyTmZ-=|CMGys?1!l7#Hfu)Dya*E^`DcqcLkL>iDr=DiOq0qR60rP)O=YCH6)VQRD>=;Cl^}1C!phMXQf1mfZHN0 zfpd0imT!5iTYqKdM^=t1CK#scs{&!%?=Lc-AGHu53lznD3UF-Vk=%RFBK+eh*A||H zH}OAV{hF2`!dXPdRG3XscoenGMSUhcQX(7>zLU#9%luj%z6M+(7+dXZd#-YaVsbPeb?_H7KRJj!?Xr*PPwPU+az3Rfjg@WT^7=xqw z=`2iHHMasxWA_QIUgUP<3STqWh#)6#`R(T>t@Y16HGbPgH)uus4rV*(YQx7KwzwH; zB#{BViXr#C9}V3`+!Nxw*f1kj;ojTK%Jt5E)ZgY?TnlXhkx6FdC5l7wN(dEssFAHH z#d9lx?Y&Mew$Z6^5xghP3rIjAuDXAPWW1eTrJJp-05Lo=DjB2j+Nv$rT68ZPLTgbb zb^L@AoqaA7Y3R}NXDIV=o(GrPc_+RH_j-iC2;~Ga%GLHn#^=)=E@rB`wWgt~+xZnk zsABIu6g1|0-FTk*Zn`lo$c#}fiJ((1glYH@WSaJrc1LB`5%{ys;}(M=W#onIP?VX# zE-{R0YibnDI8xS7){&g5v9T&J3*T}Vis_XkcLW6tyiClzPVskG5{SA0CRzJCh>Vnz zStKTj%GGm2T8xoplA+!^Q5l0wtaE}pzk$J}%3YG^sHcpWGlwEQxY(K5S3oV6Ed=ya zM&J3YYh2O!lX-N?sdDh~8Ct+YfzvGyw8@iUolVzZbeA5x{2dfXiQ7rL;>9?C8K>v) z;DwXY9c1W7;+2q;?nfSamL#l#h*6@jv*X@<@^eq{@u(kIS5q+@`vl6p4>)*O}2)H z(T1qI4e{i6lyYfmOy-Rg*G0`pT0z}p=qzljjbxr9ALSX~?>7%JVImbKtn2xr2kAil zqHx26VaQ*$M&IpWRiZQ9_~Vg!q3Rpz2`pYvHs%7n#NQ~<_i^^{_j&pHHUV17QUC}Y z44vN*s+$^v%0H(LC2|)X4E*uf`Sts~0E$=YH?bNdY zItZa@H~p>UlELwDP|rd`Gl9r>J8o3?{6>nig*g=m6>!>bPdb)OJ-TYmLAHxZ_hq>D zz&SF@7Fb1|sl%}HnsvBdKb>4D7{l7%;%J7>9^kwJHncar(%*cy5^ziqGzgq>ydu@E zhb5l=TPJGl-R ziVn!2Jy!;!yWZ)&vhz`?I-CnoDsj)g0g((VScB#-SwL>+XV;wl4Zj>NvkheOoI$d( zJTRimPL_5rg9GqN*V&@b=k(A)c1^R_K|r0K|=Ix zPt|{lgeR-QGt0!C3h|*sRss;=n;tkIQg0M3^V@qhVc@(()g=!D1MzY+*?hSyI$E2W zCE-+q(orH33gjIyehC@LB=m0vBiQ3;&hpLhVqNvY;? z)WL$QSpu?2JCDX^Lc3YBdNWat9o%%s=VeV1mF7c775HbII=TY|d_aom$By(97p+j; z8#iv})LQPH*Q7dqqzE>z=1@f>LD^hsWzR#{50jR8J*!qKM{u{jMQn9lG)WGlaX&j| z4DjwyE3msU#N!h^Cmm8%ldP&;d@mZO4pwW9L^a6j1C@*!# zt%5-43n^ViL3jJoNLe)xpw#0H-RZZEQ9RgD|04)QOy4_(*{SU_=gMXs==16PEW4d= zb&Ugc2%sOv;3@+QSu+cIjOwf45vXRf!3#O+2eoMuGGVD0!P9F1QAqTuQ>BVL-D!-u z?E%N77_o>B9w;*w+d&|7S?Cq4WH=$`s;K!3!NS23?yw(dmMr*!{;jjYyMSv(ztTt? zD^P^=pOQs+9Jr`2}D&BL+G3z z_&F1db7Z2_h_L)xTkt-F|9o{j28-_iazp)%SN~5Rnf@)#HQKn-+GO7vp&OS$)e0T| zbSPJFuQ!5G7<)%~yqeEU-$*0I#-ncn7L(Rzn&TrvQhxFZ1&EGw?VuXGPU5ZlFk zWer!(R2t!0XI?$&vg2F!B1fXhCCaXky$iq({R$u6-m zOKcy*V2EFfc&fuS72OO;w}opb=zky*2F)9sylhe!nrfHFpALwZf+@&54NhY+_p?Gj zjT&VHO9e3ito9XaY>826Sz_#+2t~-RYPV+?$6)QGp{%j^X=bRjCCip3;(UGId4N3-Ld#h=ZG>1g@4V^xy|Mb|Z zZhBr#Envz$LLI?%eL77Nf_VUUw!{ASX$GEBXbxPYOJF2)`RCKEABr-;IXZg9zvFsp zL0A3I&BBB;S%J=WM&M%7nhK6BpoCYVC@pO#6X!jg3P;GYeo~orPTvzTg}dIqk(Y{SH2{-taSj z*dgwG7MRdoXWC@S-cnS*+GWKMpUSSLd^gjE6jo)t&DX43E$}j7HOB&8=UlHRSBQCd zC%unHvz-)+Amg>a|ur%$m#*(gDxrfpc)QWc2xmTVs;NgkxRtEkjjC&}kol?>6CgWLc z;xUUpa#`*3Uw$!bZvU-CPot6q0VQ=rv&nKS z$|~cP-4pJ-bK7w8`WkI5a19PnhW(WfdyH7}NWAUu-2{_wn_oCF{kf&?hm5?i0xlO) z=2w#tCP!=@Gt8JD-{Tk6ojj%v5@K6vdq#?P)D0g?4HN~UZ9AyFA|M}!b$a(3RO5v# z<8Vd{9?|sXhD3_PLDX);WDr2xfB{Z(+ajHg8`;$wE=!Y@86)o-2`!PM^yqv19NS`cBG+yplb`#7gkr=PnP&FsWg8vpnuytcGa0WJ&{e ziyr`BJg@aE?tIA+LWr9QhvU+TfiEZi_cx>n@ae%%2>d=;^VorT0@GqNd;gwxEqe|& z7Fh_lPpiIrT8JUh!_N!3di`?vq7wf9{CZs8Mtzx3=#Go|x`XuQ^l~uLMCw2{y3moW ztKp~2=cCDDWJ4IjKaJTS5Tssd-%Z&$bWXCxh*Wj7G-1H`ihC`-Yo~80pF5 zSn=Xt;Qs50~tX^CIGkZIdcneg05n#&VkGqpP@JF18N503pGCvH^C zf2UCIv#--QQzOipAiqfV6!Jmb`r14^BIM=|?Ez@g>kM!ZD};Y)1A#H?%2~&c8!WJ?KEzMwuDX#V2R2;dxxxkyC*NpHa|i2{$CH z2aK`5^R~)f(Rm(2=C-w-6h^LMaor<&tjaE0jzDU*HH#3jK}3+;KX?bLGwxVB83|y} ze1pXr3O%ireB1r}P}B*>_}6wCe&keIlu5I2+AlJ3pz8PR##!IbD}pET_gR5fbDi{Ah|Hgpuejd)&elyZ>w%GGB7OXHzs(*_j()ORJjgu3F{Q?Qh!nuw*(60S<6hcCNh7yZQv_() zn8I!lv(7b373WIp4lG6+$m1Q+*^cZl4DjO(*?ly2>jyGg&Z<6_llAx4zwugIPL#R) z>Ua8iACXf!EKc0;x3YQT{Y)a1AU;nxd3V;XKs$Y?acl+>=v%ZyK!O*q`Sg-W zY|T{k9J555_~nhg4VwK;YsOKZ`weczvZFE}XqggSj5%(bi?NSqa2nk9}v zdiCW5MN<~bFk$QRanlS>C1qlTbB6apmL&ebd$3GN{bMEw%k(%oKmhU~+gvi_twe99 znO>>aETa*QhfZ|>vo@HXn*xPhjqFoTZMBa!@h#FO9k{XbA6r8WL#G{&|aY6JKBvvmUM9_fHbf|8S}Cl#*R z;@B@m*sd2V<@vgoVHHl%5W6@>f1AVYs($`}L*vkI2#a@4Gi z$4%Snf5VA9oWP06_oAXVYU-a%*$WVJI&o(*L9HGcB*II%=Ya5M0Ie-FK`-ZOW6!P? z)!u!B9 z$nDMx_s?02Jy_m}k*0vHJUB3tcv&!&LjdRz2KfOjI<_Ees$$9_y#$-o8w5G>`KeRg zE{^*FQl%idNpvu~MC@#abaYQTmL*@@QwB?|K8?Ly4 z*QDi>c7%nGKw7gY2*kO9(Jk>(H>>fW>|DX<ugOX>tdEfQly^Yeiq)gegD7Y?gi!THz1 zMSFhzV_?Y`XoKc)wkd^I4=D^#Vxdhc&Q3t{;Z~QQO?_<6jlpeg#8rdX=5GQn`k>k9 zfn(fY{E`rip5DeSUKrKP-SoqWBj{G(4fCS`QtS(rx2lfxN@BL^el}aLtZJQS5d8Y1 z-Xa@<^nu+#+%%bgjhpNgoBhKU14)tvZU(r8#_hi87@$8tf@S@^At0uS^U0L6$pZN< z17-De*p@m6f&~m-sqzOp!?CsL+CTNFc8k%VkSFSBLx;u&G!0aS0G!hs&Q-|SU|B>A zyVY>hKq>Fv$}`L#+vkxmvi%}e=Jrj%7p45$Qxe)-YCUJoSu2Vwzm@4ZEOdD#b54Yq z6^JlavLtXnhgmcYS)KGEz#8aBa1)1Il9R>!O1A_i@i=l^z3YQ9QDEV91MwBTc$5R+@v>wNg zGy$I1=f6!d`jJMg5TkypcIw4;fea#fP+c^iwUjVDU|>u3%V5Lg+^lGS)&MdMI3CWO zAk6c~umK`Pp#&#)DDS-Lp61!Wh1FF!lHU%se07ZOI`HuV0pJ5biOdzqP05S68HY_| zIpK9G8luYML==n70uh9%{sFMq`@sAif4a;9SLQ&dNZCQw$~HGGEskK=5WAvlNxItU z1h9Hg=}sCT?Q3!I{~Fo3AfnRDtPh{o57vH8#n{FN0cyGE*=QiT_2HBOhAm7DAJMfh zI)NJ)7Xg&*Vf?KF1m3#uDJpters^yx7(H)B=J0+@^jYH=@v*fVn4$g@9}|7c1TU4!o^w(0ZxU z%xK@N`Q3I^Oiqy$x|h^PreC>v!&k5aD=&5sEmbh8z<1Qw-Td@R%`JZ5gK1yN?Vk^|1y`)+-lr!0yk+{{ z1SQ0%pae3NN-Xn_G z5tyOqW(#gWB+ro!9T7)>!DIX`MVf+ctWt(HVy{gVwu5vDy^ksa{)aiBJ9lwAe z0HtM6hi`NnC#GJ_xK3a@O6jIIu`EA9N(_e_VmVkJ(6vzm8*ZpJ5)-@Ih1xjemv{nC z%?}M%27sQ_myHwyH$z51gaM1603zx&w4AKBXL7JiHwtGHO7uszO*#IaX3r`lo3uFk znZ(PVrMf$pHsu-4)=x1QDM#Ln8%B1?TU(q<8e}%mm+=r+aq@6f7|?-K#b8LjKa7&l-%s(`jKnSBZEJGz*B%ZKTBQQGp!AUQs0_ms*WYl=UUhL)-XeZFO^&@^9pWG=D6E$K)5-3F1U6q79+~=nq$q+gaQv!=c99AJ?bfMx2hkVDuU4vIX6uvx)RP0~bFhmeF+zbfW+fEpuDcnO zC^}X{e@?~P7!Ry#$1HQ?C2V!1ok1Uesw>T>xGwcs8E!$?cqWZ7*zmr!@B!=9WYD*) zi`%r|b!}?UN%NDS{udbNWVy1_iJY4R%(|1EEmk3;jZ9&;>=?dIx4SVZW_(A~lU92I z>D}NT(tR^)U;9Qx49o8#Urlr=&8)kp_pB|-xtU~L6ld!0`3;URAkB_4u0db3V<7$a z69o)rI&HuUsl^O(DG@}NcXQ~=Y@zP<^F4mJA}D>Mzd)-Y>>HDg1z zhCoTX*jK~W5HSCN{X`)wM{9^4tE!1Tv_q#1%(nIS*6>D-%W2f3Pa6feJQqd7&CDPM zy)Ng8g(~4YZ5E%V{WW_?@G$Q~2&bt`?(0R#NyvBUYUk{nq-Tft!pv5EJd+g3LjadR zXupP~qCHg{WN7Tb&tvtGxQLWd*kRqtdc?us?CP7noGSU%SkJ2mO)Ts9x!xVi)`zC%zM(u^^oz#7AXpq4*`w;O`mTW!{hON;Q27ef8uvtvQWgUUiG|ec2E7s5?S21R|`mw)z=gc2oMH%B{w`kmMsnCfPLT?7iKW%+utt3u8zIcp`l z6@exJmD^nmgavGblwam>`W+B6Y_g1?{uf$bA_P|5$5C;?C!_8idpw)x+{XRh0wtDz zj#t~Cb$$fRcSz`&f0E=^X2gwPakg*paKt>6V+XUvGc+Nz6H;v|-&p(brGFQTj9l9W zloT-JPCjhN+3jvtE-It#&j0}DYmUd9j?g$7iFSe({Z=&vPjbXWjiYxr6G4%$#nZ~( z$gd*z-DeSe48etr4^JpwgYl(H^BdilU@-N%9Lo%Im3fMIG>rmt_g(%f3%z!bRl*DI zI3(7ZL6tz}RC7wf-iMY$Q|~u^ZW#sBY!Zz7{WxN)5u|sWz&%TNbpY;d6bxrmRBjbN; zhCXn5Q61VbX=2_mGLtajLA-TH)fcl{fmGA1Q3bNos($$3@=F3VWej$ljFAmqG;e|9 z4DO5p#DokW5K&9$WE0fSn%TAzd?h5tocUG!`!aQgWczl-D)#Q_0GeR3z{Y^K9Vyqo z*b<@V8^$hYwF;<;<1>c*XhqiO#=Cj~I(XJkRQpQRUJM zlY!w|sK4oC2GiAk4AET~!iwQ=TvL=2nLYyV4Wrn^!+8%{=rU(kKyhAt_S(F7k5jTT z|Jvi)|G^lE3prng>q7`s3LRQ&)JCi8N@~u)UPzk4j@^>TBSleC^#rhtC~}hXe$l># zNDk!jD4h&wPn^_rVNze58BG?J2K>z{oVrvTH#`ecfuW!om0hvvywS4LAGxvA!7S$k z=SUg^=MQ+qV3PCG?G%s%=lB(dE~iAGjf>PucLsi*>%?R}L{1D=xrCFw#r0viIDVu) z-oMpwX@QuGVFg1x)sJLItk`cHXzW{NzhlTpYY?ty(^SsOd`Qt-!A!EYDZV_HhL#h z67-WBy(e`g*SS&+Mj7ArT#lxg^$+pM!Nxn|F((zFW={$y)DFn9g_WPN3&Y7hSOxRumQ;8Zz#g{{)_&b3=${1Nyw;w+HwWOE2+8Z@>bN`1ONVzRva+p@Y zvjH2_zd{@md#48BO|uL7NK zzzwjP)b|Z=QtHt+(5>;r0%+dd+s!w_b?Djh&S~KXDTo>9S0e(XVwaK9yt!}zsQyZ- zMJw$rxj<0ZdSLtMupOD}-tsL=#ESx&DFAXG$=NO}5dUEbdJ)wBclYE2ts7wJ4<@K! z)%OuD0~tC~4K6b_PdPElyb|PMSkZRdlKu`)m!h%xFA4JY)Wm7;sjWwLT0+7D64QQ6)R<9)H z5Fn0xjGoN8qoGjIDJI`;m(vd#dhwHNBDsE4?hqjUElR{3B2+ z`_e0VLX?=)@dS%t2%gO#PFiv*jM*WF#-p1D8KQNA+^suQEykjrAkf=ZfiWazM5POz zA=3x?A^GiWxQ^S^Pq4IW%y_K8g^nxyLY#osp%{JWH7E_V)Wu%bNhF>0m3JFye>~e9 z*OZNo@NhX+>KWz6*K^x7k|E4bF<%~QBXw+s`?}FddSP4`qC_F=DnOW4B1K(lg(c~j zzO)hJdN|xGc&v*>Tsmnc1->g@$#@R|o}cyCAS|kizznhn(T8`4mjb7xF?k-$rF><~ z&f9sC(mXnkL~`oDmdXV@3rZsK9m;x=m|}joGGqIs1QTiZuQS-B$%l-lyf{AUC-UIH z@Egj9GX&~jX-_O!*n~cm9{XE*)40-Lfn4uKyH77i_m$qhjI?a64UE*1NKD*-`8sX^ z8;0Orq7beeQL|ZML?OeCL$13h%J}l3LCVp-sq)@nZ-Lr>s3k5Cr@2{tKqL3#A&Zx|;5>G( zyVT{SNpgP^Rrkf}WArG~Ys?0HT3#*W+ zDHM_9*f=J-zzv@R$twOXXi>?{~$YM(S5XI|MTe;RY$n2O8;+31hb%y^J^=f$J=2oyrd-X%oty`_{g1+@rb2V_0j3P~y{6+}uYwUk=osMW3%6YA^#3bdSyzp3IdoP73V z(qP+nVM?)mK1)JjnX;d(jTXgG`!pRqM(e?Liu$?E^fwaQqJBT59T5)O(u|~#(1th~ z1WoDQXiI2I)s*_s0uPNKE@rS%70E}>QL{iX_pd}t7oE(v~ z?FTIdEdg2rLIP+7Kuds_0I>k51wcsv5dl;LkP$#f0P%p700{v!1W*z{M;Nh$5ln3R zKukbM0387XC192rqTnP!b{cW^q*g$w>bdmAfH0+|i zb0sYBeludE5Thppi;SmK_Oy3mq!6RG?aO$Qfd%J;tAd*WE()9#91U-ZA3ZuI&D38%sxmPvhC*( z$)0RX*)KDw7KFb|>CV`ac($VtYz82SD1U@_Hs~2PTLnbpFULAs zl7)HndKV^9&b>Y~Yb@E98cXiA_uhM}k3zhA!>Kb_l3~#|{l>zUi48zr^R>qy@|q`( zsc%e(yyoxE=8=mN#|(kI<_(UC<2v=n8m*jhO`AQ^XgWGN9t4`p`{@q-i;w~+mI4NOcu35 zH#ll-LP!=o!f!Q_sIfEzD&e-FoV9MX9_CGYy&f$K?a87}H|D!BCZGMAk4+PBOqmv0 zmk)Rs5xah-RYL8uS-h-^`^fCTeN^bceOAb(aG#hQxX;TL_knSrtHphA;6CCF+{Y!u z;y$gnFSCK{iu<74heZI0KF3aTRuF)Tw||;P>W{UCl4X(oWL&H*wb3KQdj;Ic&{#2}=VpV!^J1q~0Wkzy z;2X2mX)1rg6AN3NkirF)Sk55HT+Y~$vLl6OwC*abZWw zj+7Wl@Nf;RV0o%x;UY(xm5LPu9vN-mg|fUiqTm!KFuK|5gi?a*AS9)a2)C zwNR-TEJi*g87VTvDTbUyp3Y(yyYC`S!V z4<7mESD@u=p2n5}mo2sr=o=fFnv?ch+Lp!A49Yy3c^DOqnS6RusD-hJ^C@ zP#@|``E>Bbl4e>jEqpDWXyNoadKtZvUPxX_KNU;Gl97>-k&%&+S)oGAGBPqUGBPqU zGBPVWku!m zWWrD~TA|`hQLzdB(SEv@Gwe;_GuoCK7A|t6Sy_~I(tbY{$~?09Y*U}AL~)|CNyR9E zz;%+4TtY^(RP*qcwP>fbUwOhnLYYUdpDUFrO`CmbELtPl<<@xCbgh}xr(P{mI4;Q6Om4wiH#au1 zn;RP&n;IMy_JK=Ws)t^b2BLOsP%aV3hn1JqIbXe*kF93{l}HP_l6sL`Qu&!Su~28WgJ&G;?86F_0C^T@s%vtxqQLS zIXv04%K-Oef^`)SGL z(=yBc{3B?RPCm+BNo42zC6Tg--*{>) zf37jrnPwbzu4uW#&Yycy*bGINJADzvFL`AH!Y`F>ERQ3MinhC!r4j;EpW?UA0_NQZ z^%<38(frmdVMcxsRA&iy=iIUL6Ycyd`jUoLX6O?;nd2T&q{>X~-o1rJHetCoDP%$nc941O9unNUk5pXHs6<H)G)8BQMaJzKb_UranK1YCgBJB+gJ|(wTY`um-75{}%u_aJF#cZN} z49k3gy0iV%hd=ore9#8#?`>fOKof1>UhD4eSU37xxAvaa#u#^`=oH;D?5)+^h&BQ5 z^mi>0U<2GXQ2XVxn!*2j15ZCwt?j!-@wV74>gWBJz2SEs6x^~lF9)OcTSgMW3`GEu zLk(4cSP5d6gpnmqkcEdSAV7ksh{sV(2MjeB!m4uqsYh7?rbM3)?X8vY*qD`e1Vg<)fy$vfT) zf+Na>LecE4s=(A!fEp68HgAf-%EorrBm9sYt`W&5L?+-K(92Nr=w_h$Zk*t&TafD3Sj z?LK&bDQvk?C5q2|NFG$)Z0vx`Yi>vgi>!C762dqgSf(9qiFy+XaL38vk)d z(NwG`e^5_?CNIksB~DSCAfXz1a!s0=bLa`E6XXke!o{yZ%iVm>uYXfOnwnBAikedmOYN!FrS{t)+R@>t{j7I(zZ#%g4lTq}x-})S zrsSliR8y)c)uO05)v(l_YF%o-9UVJFJGvZ1EZ}SxuN)Ud*$w=~>jZoEmZS7bdP3SZ z$Edd==i-!s5Q7%KRqt`koidMZd``5do5$u65t_S!f=ZMg(i0~}n7*Y$5s|LQ5Fs(_ zK#(Ja{G?waO*W5Q1UU%>5h@ZQB4i|#gAkIClF$#1+Rs_*R{bESAa1KMg%?>{jh`jr zwxK0%l!M=fSn$}r4e5lGtZj%%=m)nADWO{r8@*bqN-MCd&91QotMW7>pVgS6#&3uP znhQ{fkRhWR6=rKkiVMdEW&(iRc>-p?ndAHwat?+4!-!xyU_00lFdl3PYzfu`V}ki$ zPq<)CG#!$BR)oSnG-W@F?#^2HFdZ-=*bcUX?O;3D4z`000pr1zz?NW5Feca&Fdu9c zwpt7+RVA5BmXkA^okk~-6X|T??43`XzEg_R>HM8jT$mQRlgMdwBArMl63m(Edm^1p zoW1jj(|1a7I-OITzZSZjobsoBPB{Z_7Bg~I{siIbK@(k&l^~}YrJ5gVcr{pRo@%D3 z`Pr~wqqEuB^l;RE*4d^g=d5+B^^d06SA&U-xn6u*V~J_0=7$=knq0%nH8s4K8XnA9 z!>hqk^HeiM&CiAf8=XxLo1IP3wlBKsky%}wIKKid_j(sYx@(1aKP@z8;zWz`G$$>b z*O2bsUO6*zR{o$c4n26i2j$Pqd*A_i&DG53I8wz{kd@Zw_Yx?`$)Z3sN`~Vz9dwB~ zQ<#%h6K#~lhaGf48lsb7kzJ8xv1qHxoEfLjE*ETMAk<0VW!6pGdpXe=`ceB z(oE64(T2?2AY=x~+GsKSOj3>tuJa`O>2eT-ET~$%v&Fl&m$ogQ4!QHh35)Tuda!n^ zAgm(R5zB~`#6sez{hVP~O5oDH(UACE**5>@B*9GC7KedkbYn#~mg6I5mqV1Jlbz+h zX1QI+x@;@E;<79uc*=t47#~bLQ(6_*nbM-1Db0zF@v(ZacB~+*BGwVhh?T@b!cyAy z!!m{`hUwl~HdY^3Ch#Qj3bY)pio>8O!NEw8Aw^28kbVg1+9tJ{3l}##1$8b`*%J+j z-q|UCP~?sj{X&SBQ9L+i43Fq@FI7*~gvz(-vD&SItcq4gE2CA?3Q0KAa;=nNh_Erd zmpSyr;up@_pa(Nc^e9*`_Rtn_Se0#dZ= zMn$l+?Z0wdL3R7jsN3yP__quaH~3>{*4$3dV|arnYQoEB7RLod|MsRIR-88jd$0Zb zLRT=hH;2(*ASm{TFN&flitaWQwn81AIjJ*^vBP|ZKGAn$FxqWdp|!RZhA0gv!@fWi z;8Rx}_o*k0&%g&OF6;7(q4@ZgQ1`{C$5mgG$D$Sm!Ovz6&HR~D_>y&>`!KrdfSM-1 zuIuD*rWxbN3sF{QbyjC}6^Z6PDqWM7cCNUrt2kQ4+0!yr9ehvg0-xbeQK=urd;bUx zNoKS${?vs>@>A|pZ&tE0to_}a&EX%j(!Et6JceKVA~yar#rd8Od~o6qCHGNn{Ir_; zfRBIYh2Js}ZsV94$gfF0)4^x>t65KwiSDf;>23Vunc^t1ab2=;9b)4ck!a}VNc{PS zPA$_Yk~Ev7vDG1k<&eb{DT=U0;XWXEnp-q(1KEA*=d5+B^^c;PglkU|2l~>k6#&hB zRF;YSj5=N6Ib?Gr+*lTYPHCBlPQ8hZKc#IP0r&A+R;oz%_VW1Za8J*s-P_A)b?QuW zUTIaU#e~Ztnv5H=sA_EJ5tjr3;YF z=L!cJBt;Ne=jd)b!&6N^;IRldP<9P?kS-D=I6p$4<3G%;>{c8lg(E)Xr%{k~0sd z)D2mLfrs)@6chIFWgj0<0siobS73~MG(=F8#0!lOF!5G2d=xeHNTR`G=YSqaO+9oi z9GuXr?Mwjiv{xU{dOH(9_*6l3-p&LNy`9qb4S*nm=713VnnG}di64)NAa=k+78#VV zemYEg08!waoXWDX$`fW$Vq1;&<(!7C~EO7T3@J# z<&TI$i8)oLJ~pkb{tlOWg|28YOo0~z8OM9WT0+J6Vkcr_8pason{)BKCk|N_JMV@+ zT6|GI{bkXd3S+xw#hBZ@gxaNqZBLB^2q~^->cRHY1wwsm?c3ij+jFb6wwkUAf*^Q$ zH9@G4H3(;Vrs1~1+BDXzHdr|7tJc5qdog|x;}1nMWQ8$d$aC*?cmJChN$C2bjj^3Z z)v;M8fpe;k*Ly`FLe>sLRv2T0W&hrLZ^;`;i~5Id-}TknV3}!NRnhg+ciA_0Y^N7L zK5g99=+;*KM<9WQx4EKMmKeie)R_WL9FnAdfhkF`B%MT2Je>zzmM<_dC0UYAL+}to4Dg9n z;0hE|9+50_Nv5_%MI8f*u5ik_o{av|FJQ%(g^N+4!5d}~g=<==cT|l(QGvm>UNa0H zVqjpv9%~bYmR7`|@gnom630{sG*;VR^jpu3SysJa2oZ2J_4aFesdEAzt2hx{=TWEk z@};pu0zLbpZy0*dd)||wp=zmS##D%zXn=P#DR6PQl7R$hh!6rHXR26LvdCNN>x(`W z;0>_^WN4sp>hbuP2FBhSO$(S3u(1b3z*itbk{>MOOVFTkZz4FUz~RnC0~D!4$M&3) zshtxnqQDLFTfQyaM%H-to9gX~?awk@ri`QDhvw)g_|;6IBJ6PG*ikUe8>~Enz%}vM z5%Sp3^d1!#_BCI-zVOJwi=GT-fXkn%O9b3N)f0nv41a{Ny-9};O*(3T=Gdp%n@!I8 zY;W38!)nKq7^HTgi08WPs@@-^;V~|{ZG8XHS8hYSTO5vIZ>>w?8B-{;%s8L76@r*7 zfAEhxP&C-|LJ->oTw&XrUa(?MBE7S{35Fg!MYk>@!>}bMr{eD4t;P3OnY0_TUz#f_ zGAF2w@q;8QddX+);GLYM8le9OP8zxj&SOeUUb3eB#9&Ot+PXT!#$ zWr158YrHkm&U;+#9pkRw(x|<;uZFvR4+>)Ns;;>1Dp>22po3jKON?5pt~ISicKz(N zsRbc$Tl_Hll#Lxk;sqQ048FFqK@b4hU<=bQ+39QlPILC%_j3^YzP{gL!ME?f(Y{SY zR`z|b@^fk1T8o5&Si>5O)wg54y=jFVcKvI6s649cx9X4}@I&#zPwO^-Z}CHWrr>X& zZfoBIqrXy^r=3AB@eJSPIJ)Z7x2XN@6N)};EQ>;HEcftP{2jX4 zpJo(UiGIW!7R@TY=0wxAfb)h6eDPQKfT9T)0Fi;vkz+jyITfaB0V-VJuQ*BH&adLU zAyXoUgOy{QM^cYMZoFj8-S8n`&{RY2298lj?#SwKfLnazj-+Htq%Qa>%oy=AUQq_A5PL3I<_AB7vAI#*@vjr`)Zj>xBbY>ACpY7R zcl`R}9Ze@7IFgqfFPH>%S`3QhYb-+$KYy98l5PJ4p_3C+Orh+{aIXjX-dbN^VpcCJ znAM7v%mqUn1D_A)d3a(*)*bP9F>A#ILoB0esd~V$%>P)18da;o16Okv_UNO0XgNTawuc;lyU*@kCH`$PbQ3VN* z$V`&J1u~p->Z)AD4it^wh8jGuJw8n~FaZEXgss(#VNo07q8>kqL5x4Z`79*@vBJl7 zwl@_4veTZP7&jXuWIatquIS7{wf(-VEd)XPfoi8cTg3-WdT!X$6QidGyGD&$3_($R z5^YVFo?5?YNRd^c$tVdVVnCs5j}9&%!gT;5b}rM7o2o3SlN-gwWfxYfXhZ@5^wS?O5^iHr!@LCf*!AJ z>-YkZ6(EVldc=Te=@A10LoB96OA_A>fAk;J{Uk?t0732s4zUR-a`$mqrJ@}E8#X)K z^GJOhu^c{+to}_JQlOn^6=+9`Z{YJrb)x$bBzFS`s)r+1B+22&QMDY&vEH=+6(934 z=M5F-jo)!u=aJRpk9ibwF(!-&KB-)*~AmB z1>A>unDYk6bl#{?JOzQ0yMY6>Lyug{-@qXgg4}%^b&8`L4C`6v4X}6Kc%$469B3}) z1br4p_&0C>AO~|ES^a$!axZ*n{i}bKB}WikvM|CQjra{@x-lg80birev=zRPCzIYF zlpX39MH>H&iUbi!dgN~45Pdj74(4%GE=zLvv3bJ=2QcT67dwsPCU?&xD;0isnAYqN zXNTc~Io0~L!)LiqxWn*i>e+(;^7RO+U;S9ipfZG@)n}k?)sJ4jyqMaW*R;XfswSY5 z9Y)z9lh48y#CK&f48upm*WtIqw*t2N30+}ot>K%sv z;iKW}@LS=l%vNc>NHfQzfoRHPh40#;;cFj@2P`oyT9S;b8=p?m4SvoT=c)%4&6!!? z0@fye3kKQ+z5>;*0svt@Ev9nL`NP*{N<32(w)o-63L(GvWXdEh8h(m5m@54M+Iu^A zn1ucG1xYQA?lIELXSV40_i_1C{xw_HW`niKSN%wuEi?w2d`;FZn&2KWsWN?&CI;#* zzvfarQyW`k+44uVQkkZ2k{nI(y{uwdcL}#{a!k#*Ph-)Iv(wO&rHZWrJ%P5LqN7DY z`TcPC{gjNm4YF7k1;s~g5%7b)+kpH3ru*3EVVhvL33jLN#Ao1xy&JH1Q#-}m#dFhG z6nyY)g3$F-*0`IZC5DAO((RNy(xosZiWV*74itTV^bA-O#6SkW1h*imfgK6f_S)cQ zz5_|^!%RrNGZ>Yz>&rcdeK@p#DX27E0i$a`0 zLIy+;^|x$5>!HwTYm;yS?59&9;15p{EGk0LH^l-CDRA;SdT9xhHh8~$7k>RO@4Dxa z3%~01lkdX+@+*^wzJLFb==(2b&y9hvO`3@}_|?dL>enHDqrjEI$fq(5pMg(-djr8^ z;Dfys-QbYTsZO+}{sZx6Bl?6JRcCGH3AgH6(D?ng!S8^dU~RDt{tfrBxvEfI*!9N- z-(TQ4LMYn1MN7;`6o2i&ej3N1@t`^XYSC!cts2=_5qoJoXwJV{G@51f+V^V__qi9i z)ds)mUXy%8qrfW=`~GAo#( zWT4Y(WOp^XH|??eIU}952sT9_kg7FBCAyXk$nPd<$ACiL7tLyPV@NIN`e`)^vY*-_ zl>5~~-}V-{%V^S&0w*RB?f)y#{*Ofa`wPC0F~<1bd#}bAV|?$u_d3Rx#-i9CBk`d4 zt0BtOA9n^MHW&OGJN5N*D5A#HiOq3r(n18Ys%eHSHz*Yxy>Vw4tvf5Gy0!S;d+%j| zwH9NKUD9KBgl)f8CGNfUjvlKqKC6Fi2xZU+8~-&^6|9`Y2j9`kfgS!eZTJ?1P|Q1m z6ur1E#05Lek5?7D56frwt!CwD5^@9VUhDXBU|Vq26l6(LkR|tnT5GM3*tiS zTS16YKQR5W)-isQk^O7*6u>10ojjP)Z3;T;6DgcS7kIT$s&JpVS>ZjFZp^n? zmze|}wrfhO`6gM=IBX{#Ru3iZ$!BN@xTC%SIQLoZPHS{%cUKX6;1N%QAcJ8bv%tU@`!$Pj3tB*s=?t?KHT(D z+;L;j4vN@q1(*;-D{jY@5+0Ia{(ZGA!pt`;IUu-~nD3NPXYTD}$8&OHvWmxYw%Jhh zvL~&|jT6lq3KLnOqJSJpbq!E;-7CQ2YJ|@}!0Y7=ONiFXff{aKQad$kYDMX0q9Xp( zO^prHD{`7g%|UWG^0e_Mt%>z|YHRz1TxFs43?)IR#hOt@&*8Av1A(q*|*LJW(M?4y@rTU1*4Of@=nWXU-Vo>jZLACktB<^`Kxu^)w!M+VkR2? zk&VZeEJhR7W}{wnas?JXYWmfUhLVZ*?xSp(KbR8d;fq9@OA^4}T;l7VBul=ziw!s3 z@CosV1X82J$j2?HkxIJ+Y1S~#ZK}@o!l9UCYjK}A zzA4On%K)W^YTYqn(jBX@dvPLq7`+ZX>UW#i7E+yVPe8ZuP}6U)TH)Mvt_NDJsD)K9JtJP}8vJS~B&i~dnuuO*iJ_}VA)foe3qfmL%t%2r~Iw7)$2!OHjT zXVNS<18b5#X{mS2Yn}-&mDL)NBZ9k7Vd#w9dHQ&E9rErh+V6r3F{|DgO%&LLB!qb? z+R_qbNAy(O6|5q4FDbY%)(vYMc890sb3grM<|Vau(D)i)x`w|gEmV7VFisqs%xXYU z^eZtAo!N2G_`NZKqdez(oT2^G1Y4jphpSdE7d6L5v{u|XQ)p+~I*G<0WsDu^0Xwd1 zT)Zl{6gF>-^ehQhJ1+NenjVQ>q}$`Fdxo4*KF8{HM=nj}1;#CIqM#5~iEurhv7|-)q9hqu46Ik)3PEu!>z6e06naVFoWZ>#w&ZJu zj0j)ps_fzD#9qNeDHt6x;VVqz--J!PAf2BFx&OmY1~i`dWFodb1%B)^tkA<9ftonAc;C$ zjI?ls?NTL<|B?D4jkFF#RWAh*Z{4D=)X?LN7*>bX!&f`(UbP`owQHd!iw#|`4>?cD zI&3~83NhMSA;Yx0-%jT{E!g^++RQaI7A*Jgp{O-=S-!9E(!7B z*ik5a)xqob!M(8XDi@M>xR6)p34~uezbUoA6C8%asMXoDP#Ozjo3#A9LxqO?;MSYt zB8cN;MuOz0*fb!4@?6mjwbE>MmMqh9Fz*~kWTEC}HwvK}2o)VN_ar&}M7I(p2V4X7 z;6-btDfaLo2VM5lRv0d&R3Az;1qj`;7pFvwNmBQZlq0n4O* zsbB>>qS7cz>P{`iGoJRc?u%$VXEc0@C~U2T(Ss-mliwE8l&%xsrWkM8sTlG#;63VW z)NOI(O19Ui2x}DQlJs6hJd?QOv{+uw50d(&MOr^#VetG{$aB!jPcvU(F0*FI8CWDg z!D7k;sg@J1<6J9wuX3DP#@2C@`hZWsHiWE>_-%)3v1>z zh*l|z&BC;L6vXnIc+SFXo23Z42W>fJHJ7;{987P$COg!Bm9mIJPpT=THU$G*+R(Il z@K?C#nE{^ zTE4pyorCW}s-jU(zKEXiHJ5cqJ!|j3Lwf-Cvwmw=4h&Kyb)+g;ae z2J}+GD;1%0(OLOROjd(Ay2qcYf*^3ib)_#e)J~%9y%cM5ZbxZdNh7Tr{2W)`bu{e7 z)u59DT(q5!{5Hmzlabj>5mV70lLiD#*wf~Za6{m=WR^y6iV;OPAJov?r>qwrL7_U}Vp zfcs&|8`BD<#-H{4f}!YwH&H*+nOIN&v~5cF7x4PM-e_uUUq zt`0VW0!!?AO9#C9DFH~<3 zgcE;RZT=Oun5aVOUboPYK8#|Sw?!X}2YdCmVXw^LR5RIKF_ScD1xLdhKtJPFrNq&1 z5kG`i)})^dQygThSQ*T#G=6AyD7}V*3%;_LH{Un_OJ?TzOSRb8_?)-#uS)tKvjJON zJ2E2P2$L|!qC)#MP;NVTjRN#`Hf--whwWw@wRJ4w@G!<dzBfIrnqt@p!zdc zx^_Hrz?v11m9Ev*2tL2-lW57vHBB0>}{;915m0Q5g^Av*Yj=9+b^xbB8spc=tDqNjXkmqUObeNX3?kvyCM zs|CiO4(x;`1&y`kHjL;K*?g@oh{H|%t=n~R{gJTEbYTZg0Bn_14zTbny(|knHhdZp zOJNsAQRSSxBG%V~tLa*ZIb}Jn#GZ`Sui2JmoEf)Z_(LlivsqvIZ@|!jhOZy@%3gBq zmCNe*drn+0rXXiQ_0Kkq@`s%R7vGIlM4qv3DWGy~xCFd~(K9sWWvyvif=48hqS&V@GPEOB2D|5^wd|$esnie5Ujcsf zn$N0*XElL^JED)6%Kg^ItfVpdS(y6@24X(Zn%JbgwUe_NO{eTG_~wH&{I}c-S%1(U z{Xt*8lH`)^S*XzTQ`WGA*F1#H;fyvSc^zTkBH)<|=P}fq9vTnjQr6|kXj65FZNWp9 z>4;#>r6w}?W>GFD;C{T95>Ae!CqLjDFBQ%w3G_cmU@)D|D9cdOWTM)Jf1$VhTxV6D z-V!-1Txp!Rge4!6WzJ+zX%$k3_LLGA<|MW&(*$T~bYp8pUa5@$fTp2qB9hj3#j@<^ zJly6Dd(n4GNrfOW=~?a~v*}4L*)z?Io!v%lNs(sE#`ms7$c9T(-0eN?#PwM*OcG(f zD+sauM$3Miq+yIj`P8VkX-&c^ye`jwdYEq$q=4z+7R0htyv_W3ewAQipbB&$uKTrD zITOs^aP`ZTiM9uc@;f#QWJ}jWB$ZlwNs5Lf7-VZARSzis|3>fbShsV6!`(+1Y2W`! zW5(^XEOlOyT}mhjZXhHy_AGX(mhB6f83ic<5g(qy?u|KfXp#`=eP&jPzxHgBvwDB< z1$48`xT(Nt9Ui7e0LT?DO!j)gqVUnFIm*o)sv!`2MPQjX7H}8qO`wP&as*xs=~Aw` zYC061)7~1YYunwtO8zj=4+GlbRlb?uzF}|_0t=U5>o}l5iLoMlyK*MZW;NQ67=x)K zK2c9yMA1Su`ksJi{-8*Kg2Xh26Vmc0z$6mRY2*c-XB9jqu<{88h8z#8GdY zpAIwfYyX6E@_z4m1Z-pXTb-c$Ca2AqKK1nAFvs}a!bVxiBN|ECcy$p+t23toFW8z? zIY&FEkhxko1}F!EVuBtvrIzlFsOH2Vsq6niQixo>49hxZwI$@^JBZB&BwW;&$(0fw zJF18=FK92fF15UFP#lH4aimkYWU=cetzR7rg?=}Y=%W+m!%6C383?_PkO4xx*lLIU z*c3NZ;zoFQDt7C$CTTn*pF_2pY;nuo(Dz7lpZ?)2f9W74**3~RB!Dj5BQ<2^j|yvm zt+8{?{Yh<{Vl^&1C@n1<|0iFaZ6jxtbvLV6`Pr2&;g}fC{iF!!q z?7%e4)n8Uc(!-|?<{0W8S|~TO^%`N@mmXSRPu7}A#FDJ=ql}Xoz_@#;bPtBt`xcFp zmOK#s)$QLv!n{q8-+_TXxgtDjXXv$$)Ay36TwxsuX!-(n-1)EC*l;+-)+Kx5LPfXF zO)n50d!9Do;)wEAh_L9gOFaRlh~Z5dpI(sSo&*f~!qoZ=9lH3*_xl`Y<4ZqK8M=K; zG*cj0+=aX71$l_?kPD5BeUhA;Ovb3}u__`U(v8;D+Oy1dL_EE*BK2-Gg%h?r!`9qo=2+CcZfWu~w-q)5;51tq zM<0oUMyp;FPji5!qWXnap%s8m99uy|Vx_7-bQ>}c0|%xPzDi_sE7$jFxXL;*MMFx0 zxT!c5Av@}ebt0cYn%Co0x8aiKj(S^U_AI0w>Xb( zx1!xOd#n)X4<6V`G|q*PEWRbB7UFVBrl*a0F0+W9h6xqW5z*JOj(1a?Si{hcQ?wZ$(mjT>nTuh@w3#L$bZK*d z&eSMZuC4>k7KTE0bzAd9EClKqAyba*ek*p_l3-oNhIA_hXGi6;`%b#~&ecx#HXYy@ z>}(Mb#}az`gq!d>*XkA&qzO3VIAvg3F|Oh)oyhUdW0soO7F-)=pnB16kF?V4D-`Pn zZlINOnXio3Q))(+*6$_C(s?W0>WL{eHgn{akKr@fPrPAXz@Kd)`f`n4rpm`RcfU?%hu616z++UxISU&+-I%W!EDUG zNG4ZX>@R~3OCVQqkK+Pd^#+}~H}eECQAb8pzrc;!MgLXtMJ6};*#KcE%o3FjY3iYK zJZ~C0XNLMs=jPb6MUlr-zWBikVmbCPhDHdVTO7DxQNx9g+{=s+5L~!1RMo%PX$V!t z>M_icOBfQV8TH@>h?`So@B!oIRvB!-s5z_*Q0+ z7W&=Sk3&Wr91dLZ{V*nkuE-9V9Q1t*Q#Z$9ksMP?igL*Ys>zNS^aX_PYV!&1DK>o! zk@<2@y((>lk*NAQbi?BX?ylok;jhhWP}MXt@{uv~x2ly->*vu^%`ysN@gEqhnjY9S zS2y&XOIG#`jM;irh2EZzxsbSJNr7wz*mDUXuFJ?!6R@bkB*eT|Gl&TgBNH=bW&yD? z7f5bnw#bVx6%r@y?Q2)YZ9C~s(DWoHqtSiY@)xvxDf1b0{Krhu|pluz6lNogZk@u;grCeHL!7y2c{nle%+3BVd@j?GhllWjE! z>kE}Xb=toDsG=CB+xGT63<~T367y<2E+)kUl}&*m0z5=?G=b<1qPR<6YhPn-iHCfN z^g<~e&0!D73a2TX$qI8aE%2=~xvPliULl^90aX*?Plka^)t(|h=d|W?BtDCA*-lcU zvf!J>CWCt@rGXSr5xY2q{V_c-R4Jcg<_1sF401zK3^}!8Z&I zxO!67Jvinjo}bZEIKo_+bDn;8@%ssBXD9LN&zYN4iT(#H_Pr(uU-o`o z)0oS^G-$LTNPY1hlh3bsI{Mn(B3_qAQa@89H-&YEDCG9C`e}}MkE3{yw>|Rw` z@&#@md* z8Bw<(bFHrD!h(t^BWo*F*CRX4?EG?nkv91s_S;^#W0KWwj63w>*ey4bG}}Zl}Qm_;Az#s?qm}-oRox|a33HrRR_J)*#*ZM#wPL1=m&A50Tc9V zBKL+>TFyOsmHu2ms85zBKG%8W93QUglS|!_fI=H~Y>%$yqT}$!J>RT5gW<-tJ-k6W8`NslYmB;ukkniodz7vqEzHUYI5|JFLY z`SQkvtLapX7y)iKzcc;{pwX@eV<3z^@R!DUm&jK!oTDtZ%3B;>lp^foRg4Rm5x=2u{+zWZQx`dh zCCVu;b)gkSZc#O<^y-E$K^D%49K122I=SU47xvW>87h*>Jj;P#l16gq6eyQLhGMy8 zh)e^V6dA`BCfMU2Jq2N9k1Pf|`xr2KT#4jZA)lXsluv^mS~xcYT}};LU%ym+ve2TP z29q@J)<%r(hL2`6__9aslx7yep1S*oH^LgzR=Kx`MPuZ2@>Gb^Dm^VEt)ppIPxMHF zj?Vy7w4qvh{n)jiDBIY1l5#RCHRfzsDUiowzaNRc=L9}dr(Nob3{bX7mZu~+l&yIh zmCCqQVQg%Vm}vSwLBvxI_b5Lkio=ICgXK10789tp9%NJ29GP;0*a$EQB+&rw#Lm|4 zffsU8>t~*~o#KCe>gX_t5S?m6+h3)%b4Oi*H|sYfLI|ouES8y&0U9BJLcvx^#`GPc zULWnfTW2Tzf;bIWL58N&M&5V+7!^w=Sofd%R1O8MKhFfE^Ax3{KMhhmJjO;uS$AZj ztQjIgdyKG7^G32?%P$-(OHslAZlcD~)+Osn=inp*O;uyks>|{EFod-1z0sauiS~h= zg?9eqco%#jhp;Mpx6XU&O5sX!lsX?F8i~7W@%EI zagb@9X|r=}_8VQx+n@;m87R!Gud#k2F)B9OUg#R>tbT<`CZ{P@RSlbom?M_|mF&r| zkpH0Um_b(}U5|sgGF;GhS7s~AgBm^Y34(jAky`4TuV-12eZf|yC3X(3YM25ZVZw?5o8O6^+vA5r?~f|V)yRWX`!yK(7bMMx zkdUwXnGTxVYBI&b)Ww3?%R%K;|0#%666uw>9fkCcAVx?d&lZX!$ap@9qaj&m#hMAS z%=xdC8&=a76S$g!mc6h^l%Ji|x-^|L;`_?lw(y1F3yvbPXY|QcS)HUs4j3Jh`tXxI z#tzwSW(=nWo$>o(?1?n)s9w(8f^?6VQGE#q^!^OR#F5{K9|bS!WbTll+%RcCTHGQDaS1A#Fx z-~^6X>N}_ur@oYa_BSM%+UN3hs^&<2F64GU5S_V>G1_k;W{D8fo8M8*O1U9xX$&BH zrH6=0mfgIAEJ-Bhymun|QC@QgxN+BvB2}p+eJ0vID(in&jT_-wX}mNkA|<#$_tSqS zZy49a^Mi&C9gGCD2^i8TI`$O)(nb~lj|3q!Ah_>91t7hItZoKdtcenSZuYTq(vVr1 zQz!^Nk;^I?MHfS2m0$VLlThgxF?iP-?@FNakHt5HREIuxj( zm1HWwA17Zkw4;L@Kx_+wqr|LvpWIt(1 z>7b=dcRD%Qbw=y?Ob`jqmKSrLZAME9+zKZ<(MtcdtR#&5u5-;yErbd$z$%O;1!+|s zZ zWN_CqTQamDSvW2Q!95i+j4jsigDVK9#mLqq-rE58CQpU3ah9ItAVNw~ychQ5D}isg zsc|cUX@FKHvg;u!0ZH#m%4+u++&UEUkovIp-5oV<&j z=UB52&D$p!Tey>Ai6hi#{zOWBQ}9~bYm6ud;Ny!2zLmKHO+b^&G$6Jkk#f)xf9H3a z*m68X9vH|ah1F( z4KK%oG_vy<&(an$!JTy`eB!GbOgW>`=xQ?;{X(L88gI)(77D=s^oWImb7rCMj4nug ze|8ez+kP?Z(;p^As?x`}J-a>TP>TLQTM4|16;^4RwhQ$H8gxilp*#CS{}AYNCL-ea zZ^XnNjTe|+VO9=4S|$wCy5umi(T?&Cp3#$L&&`EmC(e3s>NY)*B9?5R$$iD0g^d8* zG3RqM$dJ(pnfGIx+upF2ue}QRw34M=391zU8y#pju0;+2m;DHccoSn^!E|#yy6?oq zC~VL7CEH&UF;oMySe>uE=5;CSoKZwlUY4;SyRNI7L(mSlcOhB4LTV_1ko(p0@@qi- zSo9;B4CYw4rXQ<-GutiASxk`nNvH7bYDOPD<9LPe_pXl5h86JrA^IElE zwlnE$#T3B-zU+z2s?`NO3+B<0h(x4@J0PtcJ&X2Nt&zPOla^GWGyK&uMD<@6QlmxA z_$ooc%^!*i<=*W{f-*4lWkU^B{4=mAR7LbC2vVzBifV7Oko2CkTfE8(PGhyB(FLP@ z@2`y65yo-NNOxgZvlfi&Z1wQOVFr3R6I`|%D};Oa1>LEKnCYj>h3Ke51IqIo(jtxU zV+?Bv##1a(?zJh4TrF+q!7H%)=SRU2M}Ks}mG=(^I1c=YzxrJw6YpwU(DzCJ{B-^E z;l*y5nte4790e8(nzUQH{W9qgcqF$oK zE3*ew2bOFPdWI2iK%^|M+5j~*G3+nUM0rvQlwwdf$66M|gl_&M!#sN!(g$QYF*Q7X z<~;Y!jsz^l8IbcFwU)VYtPowkk$puz9#$SR-wzcv@q-EDWW^Q8s>B=z?z0Wj(A}FS zG2NJ%FwqhGhoXLJbqjsU+XC}B0f2z|tn8uYPYtqGNRLz6Q`E-3(c#Fz$9Oj3mt>dv zF03Spx1RXFvO4%JK96B+!f6)>x_xPU4z~k=Kh?5PC69Vdi9;O1>pVZo)1FA}PKJl% zK~rMPlwrY-3_u%=7wGdiX;Ye^|3dh|6FMbp6WBaxb<3Dke<5~%qX#L}AB@vslznNV zZI6gm9G@ar7p`yt&n7cGz5V2|M{#4;0V1OTsy&8^lJ(vWlO@UCr|v=Qc>?9*%|42! zQ)60!SQ6YlHzQ>Zhks*pM7tPW%Ks^Q_`g(T|6o!V1SO?d zWsUvkbl$@+*Rx>?Wj-MgKuWp_-zkWYt5u0Z)>t4vW=s-)f>4;h8PkeX-8E2R=OqL# zV7VklD%;gdUnWkQi9`uz440e->?a>)OX9@Dk{~}Gsk@0aXD|WwK&)4;uL5qw-zE@? zurP^4$;kT2&xzcN12Uddv?{9B{~%~t6WC?v7CFG86Qa2~L(Pn21N?j2Ui|z19V`)x zkCf3_0UB%t12h}Y!KN)C0verk;<_-_K4S4~F1@+&#C3g#c*ddx;YM#l3SeJRAJzX0 z-Ee*E%JCIAS!Uo)Z|Pg}A*{EllFh*@#U|=DmBv7G19AULuR7I5CBsGiA0X9ZFz=xugp5U^dnW9hA zraWqi*O|nt@Zg}Ro-6OcI+IdCBG#717~@WC9hKs+)F<1Fgh3VJcxlCx@C6OHY9|46 ziffgYw?z!V(!>^<=>=apE`SHJ$fdgh^9>AVdgn!_w?pu@nIg)iG6@CMAAM>rkuJ%L zM<*QFIp;v)5ig*RS2lW%Da}uBo1)|+qD{AYmP5@FUW3H%t?-J1&$zIDP+M937~V@M zz)%mpCz{S3B;EG{o9k0!LW{lw|9B`lIPc!^ne$Zi737C}C)mau^&7#X5WAux@3WRi z1~4G;_6O1K;vc(18c^AA0fp90nev!Le#G;2S&?ur2#7qdK_zlI!E7Jnl2$O*xH6=H zw3LcSxIhGSe{0cVm0$WE1j*G@)Z1Hp$RA=ZMi{G#6f6UnQ5Y)C(viw(TlVo@FONEg zI~1j1DS%RK#c0C5M;$Yvjp}=7gu9e01Xt|DeKFdv<+7ozDcWQ+7sX?%RF=R;I_Lrz zEl=#0qN4S9T1R?j*#+S~dWVDaSiSiSf+-WKL zX?#3FfpCgY70k=WSgR1=q>;tZI1yD^iG*@=yob-;G4L$K7{UhASPw6k$ z6k7&WR-4UcA6)EHah3wxlK2(3dVI6dV-e!jURGJ{eP6v%;5p1JB4eH*@IsBd{fZ?H zlEwuAiN`h^=lxQoiY#4=y!`fk(ZxQ;*3kRKY@97VaXc=P97xwIaWRLp=LM4BM*m9(TRRDFZH=Oa_O35zt zHxQ+yPSr2;j2&sLCV@>Ig=D!?XJLjEif#vk{KcWBNRr~Vv_QBZDeA$I zq!i~iKdEY%BwTb72_04jRzf4B+sWX@VE+bO(N1l!L5id0vvx6|#wZ}&M^j$3G?hK+ zaI}I1JdM65$kf_J_^4xZkY&57yfBU4c9R;gwCYQf#0~6H`jaLhmrk<=geu z{OmBTG<74dlf@n~s_hCe5#pXfXN^K^?#lX(Zk7w@d8H1juUJIM%#ol-_w8`3w;f#k zKVnEKc%Y!qJ9dXnb<%OK8jIf)j7ZLAtq2nWpv?Jh()onaOs<90FMcdWSO39gP8jXJ z$eK#%S~$B@V<>}$a`afN0}{B&>y^h^VxcYYt~^+9PUn{Jod^k0CHaEDXaE{HxHy8i zk@IRCkLWZ1lE3T9bm)`(?bo!l1@R8S_I_GgiyV66G<~$R1`?K?3nHlh^*Y2O{RE`{ z7N`vvRBTaGS*nQ04q;)0&Txx~sJ|?!CJO0PAr`dSkz&ZFtir3iDFU(P8%U;;1aJ*NaKG=68A8SqS{z z^HqzOq>uBEG)Uhiye~vV!wiwENc(DRbnQ{!`FX-QvQ-5JG(SB z+Flyi!1}A+FQsvgXR|fhE{dYXS`>z^MhA_s62dTw{AuWzAKTb15R35UrKpS`{GL7a zS}>@!x@{ZDV4Z`dMH->uc0!9uBFDHRVqmK0w+TsD`|47%&A>C0Kub&%xg&u}#DC->)A zi9yT>+dt8}Ni(YugCr=za|nxLLf-~^5ui6Z@pK+*QH=blwD7JoSg-v_usE^_CWUf2 z)H6vuD1N2=R=Qcw5YYk*`GnX%N?iQ+@%%HKcq(I82jczf^+@MJx66eL?x zvn{McW3t(IJ zaNCA91^4l7l1O4BrrM~}!>}};xHZ>}7&!)#T0J*J<`PR>>}r4_@D)EUCB`HK7EYo= zf~hcU2WFDTYX$Vndp<0=3<@7qN{W1=*q`?9d1IPI3iJE_tZK8wKsA@KdYK_?N7Nj> zx!HygPj+-6uiqF8v;vns`D;%3^llMM2;IoCP7hv z$EXM(cp(wDDDCuM|~9CZ?)$$b!tdH_hxAN5l? zzD%dy^EU=vos8IC06O3C%XF1YKV+#yM00^b)+ zlxFTt5Cs6b#G&T|v|JNp*!7r0xM+$Qe?;4}a0owTlzIKXbBt(D2st-dbkmyedOnSg z#a0Y_??<_tV&4`=BT0T-y7WV}TRu<)rM+X*e%BNTX?RBlGkUz7qa`>f6cWv7PTaM5 zAcUT`gvn`Uw4|A`Bv)_MkxiLw@XXfn0f-~jtp^yXM#k5La_?Gq&WB}83rZ>qa~Fty za2BkjMsy)eRaDbb7Tkm5X>^Hwv*o5L`mvfwDiB1BB*xh}G;j`Kv!y%!q8dry{4j1a zHh_%rh`>vCjZ(f==IH&NWf{W~>P6B#UNBY!2|D7U)Cp+u+!gmTB5u`*1rH2Ki$q4? zw3n)Dk8#@rHZnvrEicEb(#lyyjPD z)?vp=yJP(J6)<{wL%4cfVI|$}vGKV+D;FKqLKka050B2U8MOEDNB4m1b z3H%``3cQB%G6CX+C%Jo(qa|=rlcmGTRuM+fqCKAVWy>6L_b22cp=o~e(rUjgI>tC> z7qI?ngkjz(3nohM7&30)i{%Vn%972Pqi&oPfB&X{jVktDr6pYqX$HfB?z+p4fKSVPK@VUw>jYcG2s*zne%kfk!wgqxzpdu9R>e?n4`n)wNvpH2rYz5;JExt@=ZZ~SXQcKH;=@5kZ@BY6wMoa-+7ft%8B*62|+4w9uEFG(pw7LXuXeZ(#UzoD)j!^~uZjKsfA=-g*4 zQrJW9lfjch1`tBb2OzW}%&2A`1O_Urk5An)){QzVdwtbgtCfL(5cWw5|6XPN58>V^ zR%k^`%6NzG{*WWwL3Mw)%+Ar=X#UgjiQp)v5dd#EGmQfYFk5dSY_+XBRKw#hLbTA7 z-iT1BNhw4BJ)v7fAmN6LmEVhyc1Q`G?Q55sNjXb?9@a|3$xPCwkJZ$%9seR{=4iFj zL_I2JZCxM`)>ZaZc?!_Hr24!OKfPL%l% zN^_e|mRxj}dTmz)z7k+}@64sjH>cMg3~Xr9-{C@9A4$~;N6mx1es1;=D2`>J7Mis< zSwhSiC2Q=YESC~0UIX%RHvfgAP9-j-gmAhS5P{xnR~Z)9DyAc_o~WIh6L5$&xrt=R z=HyzUh&Um^V2FCHh$6p$9xiVOwhP?!Srr*99>igdsVC&5AmQzx;X%}(K_2eZl++FI zsv*-CBP*>BEAz2=qDXE~u>K?KO~68PC_WzFNyb4N^fE`ky%YFx6TMX%ug>xGtKLD{ zP}t-QUlv%4>eWTSWKG7?g%ld1aW-eD9tg;kfHwm3o9?ETQ|@u*GA&_tMWT%ztjGa^ z^t!B=#ga|;U+E}UJ^#&#i4vTjl5@DXA)wMV<|SM88RW!T80$9VC7+sTp!$=*G!6sT z{#fHBoJ?wEtu2U!9sxkcw*dK@-(M2P|G>N?$`*v_0bK^qZ46QN5vLDtTMN-&@{KyN z^7_-t5Os4nF&+)jB8fA!ZADtFY6 z9!r-dHjulp_k-L-r36fdsgqAjBQg8(sg*K$_Z-_FF!L6w3l;a81LfWE$?0F!=^hR^ zqRNQdEu*+32NJ0Q0{5Y`32fONV_6*>>=k5Dl@0e-^(BMEWA_O>=f%%&-`g@XX$A+a zDRb-Ku^>|MWT*FM&i!#q6Tn#bta|%a4}V_o*(WP#-PJLQ$GHCge-z(}*$F%6TXxJD zTugr(hyNGF7~Vs;45^HSxV{$IsvchCgBxPYaPmY)TPuKAHnUw!eWd~lAao^sQnz#* zO~#Q=p~ale^xxEsr&nH6+@*d)l~FoR)#cju-ksoG7-o9QKl{!G~<72t4yGU(!9atVLWcFB_!*7h}Ch@s}w< za%Q^C=^l91FIB6Y)CQ&9G+HWsb^?ln*+v7+4;Z3TVjN;86HJpPUzpoe5$wu!AwR~Dzjx5T-ncNQM>g_5O~#7jza`vz1pT*$r9K1NiBw7E2#_Bf7#N3d z(uF@vT|LrF1060PK^2C3pWRdi5cH~0R9K+A^MQoR6Y3%NWSz>$e??f9RJ#@cS^U1E zKh7N^J=oC1@bejakV!K5`&p+&{1xGxje8q^uq-ZrACyN9rl3wogGwDW0CcTFH@zQ8 zOp8 zmho1W&V-jcO2N!QaW#L;&N#9iv`mdS1fkD(wT#O&J}4FYJ;{Au69y8XwUKd#WH!UOWvPNjAhFu{J0F4DA^RDj8AvA+g##LiG@vN*~^H+*okB0i9&5R%rnB|4D|7ECc(+Ie&<2k)$x@ z8=7^39Pn+Vq@v4&`PbQi87#-P?j|fM!{+~n4k#(Dj;++RNEC-fXxrx*7LmR1i1j~bos+pFHnX@jS0_M*p$KU3tlL-MP za7Kd*t!R^g(@jylS|@Mqfjd&&D!cVwP|z$eS9|&&^#B_w&`w z2ew&M9g2u7mdtWOSHv(LALwE-wkf~axZRtYDn&9|(gTWTS!w;ZTf^2t zp{EM3^CZa@ei6VR#@<$FgIoD2X|k-{7mgA4gmn$@BwTC(SWxNn2_iQQ%u;J*Gm#|4 z%fP7#H^4E02L#oCTM|brfhzZs`o<4u`v(C700Odc5=0Xq1~f&9Js~cDmcaT@RO22R zr@1p~BgJ2DSD;pQQ>WC{tT)GF@r{1YubqG^?a)pR=tekK#yT4;IJX|qM@6V98KPkR8LlS5D=#?@`pT-&N~)}h+8 z3D=yNIR^|jWu}|{cwNm{{}58X_|x`p z*I2I=NT9CsQNbx;C<(n2A5>Y21~YEdD9qzWm+|k?WySK;HfRKvm%ZTQ()E?qqTcQx z1D5_3yhEL-Hpzs(&4}G*n6Ge?1Z!Oh!eXj}3kYL+E$6^qI^=QHIa(oT1DTMA%#XUk zYiU=?1D@_nD^a5DSE~JUJ>n$pM95>wcN7`&c%3&xc7X(iTKRY$@~AdS6pF~4IkC&> zuyGl-a!71`cWK;O;WMp=DZGK_4kn#L6^IoTeJggSWp+&B+2-p~<6;_25(08rHQj8i z$K7aAv8Pwt1LVXIp%rZ071U@xuzsYn`ZVJFjTAXRFlgxw!`tXl*JiYz6`pRrj@|a3F>y-QpHLd?}zhZ$9kPgmFIp znT2c@`e@g}zG|X!-3J-{xFQC3+P4t_39)22Ers(4aOK7dAb>?bj`=o+gNAe9?*Xcd zJi`&P^&l^sl&|rD2@}TV7}u(wbRx zoQ#u<<6yVW_xgvA&Z%fW`UheiZ9c@9CmU0(6FF#%skrglAZU5hoE&2w&?)!?g6eajp8F*Tz zikM-4wh*D97r|RC7h}*z5s8S9NZh;I-g`@#q?7?a2`&j+31rl08e4keykNUNf4lN_z038kuOR^n%O6(gg&h8Q zL1+^)zUy83w0qRHBAa)8-ATKWL+lni{1L2;tH%*oN&J=gkKq0!_|r=2v(m^uYySHh zed4z3$MSS_;Ck|1NN_RP>)7X$K~vJCF=nC;}0v9c+MS)eb+sJ<~#_C0y2ICEYgZuL=R|r z0@aE(_6OoXEG@4FkpS({;_L=QoE6#Zso2-{PvW{8(_e|}Y<_$%vN@;KDu322E*Jl- zQEvYAM%MqFY30fUWdc-JBLRsmdo61l5g07?I2wueG1|u->E>Zi&6hrZJILcjK511E z38WV7D1pWKiKFTOXu|%iRhiF9CD6S2N`_!fn@`I5AdP$$?IYqN0V1FLo059YW-Q64 zm0}%nR&tJg3W@J}OA=XqiXT1@2imgos5V(ahn=~^f3RZ8epVjwxM3~EykO>VkBehk%*p(!*l4`Om9l{@I zW&6}h3QU#4vMVM((8{q*t)!kd9kSF)%7#jZKG2eaVb>Qy2SE@7JrJ}YST6`t9IH7o zu^-3BWwkxPqYrXPhyB1f<u(>STE$`LXePp67Wp8|0BBN&fdhtT)mbnKxP6>xoD<_+B})L0G%@fioFcBAIQBXYPHrxS7TIwZPFH zEzZC4W^vo;f9~0Yc>kTAwh1}!KF958B(r_>ObJ&J8D~?gDr3kqS+=QF6)sd%L1J_w z*EY4P(nGjJzHMq%Wd$l;p!m7GvkV+r6f-KeCpN1hR&a#?hY~(J=vWbo zkI1%7tw5l~hlv}eT=?0G_J&{v-CAoc=sA0@Utwhxg+QplPX~hF2gGyqFUHS9v#t># z&*kv_L7iVgJVzg#$#!zs*=#$;v25`S{D3@%Wl*L<%L2{$_iTT=WZ(aX$o564?O*-t zRMkRtHOq7URZEKPTRSXjmb=?0+iTW#tK>PiOZ3N|Y*3}*QMQKu_{Xl~vo2XB_aXdl zm9~Eg*gCOF-xL=R%o(hpt@1o5EngNAf`uQINlih@5Mfj*waczyjf$d@*}D6*JJ+AK z$!V3uKkX8fUEea_O9#$N*7Cs?DJx&7wp8)|S~gE5>f!`r=zA*O5)Gt9fN93nlmL$_5>B*O6c4 zI@#=Lu)4D_)Y?Y%-INYj9+0vql(3(bS;=+b*SvK-t;|0wUoR_b#J8?LbG@okt^?vZ z`%`sScdnDYNTKAjYT1ga_f=1*SlD)o$+lI>+1OR;$&?M-{tnxI-FdDmCD|t^ah-V0 zXcdv|ws}wcB-7?;+W}lZd!z7a`UuMV@I7tha($9X>yFyG0u8EK7U!husA<2ZK!d)w z;`dS9&c3(XSbKk|j*_{;B*YJCBr%2z(*t6QWcsL@G2H`)>^h1j2Bsw>-k_lf6ioY8 z$#qE|I3t2IKtN$K0*vY5@1a2^P@MfF7H8jx=Rp10Tmq$8kT`-;U@?%y23avouw|;0 z=b}9KR8v~Av`lvAb<1-`TxY-7oPBGjoQ!=>+p4P+8@Zl#d)}txkng?!^!cjVp0?3l zOT3rtS0?*)SC!0IoV~hg`KF`~p=7pen?--@-7zw9)MsODH0|$mpkxwkP|yB8$t!Uk z{qKK>OkaE``K)d4zwgWMzwc^)AJ+c{xOBHHV@E1dwzX8c*vv%;mdL_I3mQ^a%&i@wQgA_r z9TXPKAf+YVIKl@ml3-#cO-bU5CD7P_C<7s?Y%{YpM1CB8ct(fmECO@WsI#dz~FGk5>ia?gcmBnc)^C<6sCn@+b12ig~7CziD|91cBtO$bJPKZ zQWx8^>ymUR1BDwb#Nb3}1{2I+TOp*j{Qx*ItyMCuwboh-UNHrR?O&zxd23L88dLSM zLcHPWYK2_0#q|RdTx9VIxHSYwM#h_3JpmzFdE!9^^63TIl~WrsCZ{lDOior=%ZUn5 zh!ajp#G;&{$R?zmesBq4LdmIy*UqT}FdV3|K|}HVvai%k=>*U;F?P!r3%TmmHdWRmj#_eRQ^tcf24TT{Ru(^SyuH_f@Zj zu-ZViPq4d&{=9a!_|n-JC)H|#IJ^0b-e;|?KKOd~yZ7_(b?f?cclYeA_Q&-hYj<*N z`V-iIwo*zd#h|-?*0VzP-CFDJ)>><={c3EGIPYI;>%O&S&rw^e?`rYBwt|;_{i?4| z(iZW>W5Cem0zLeJVATQR^FS~3yb!dwJbj4VeYEEVltBu?rl3!M*JQIwa8!sG|iATjy^ikW4UcW}G?K_>f=#z z>}4d;jK`K;`LJalBZ*|-jy;Sdid~qM78~}NB!cCCkwlrxezCD%UqceTYMvyCYAzYZ zNflt6z(c$o zbieNITf4*eg*$3NR~rS+U@vHML(WhBSb~qs(gXajx8*t8w&uYR z1YMv$@qc4}m8X&I`kL}gB8jp_GTX3+X`2xH;M)f^1#sJ?k>GM!x0CI&sZ~|hu2O99 zfmj+Xj6;Hva41b=75m1VPxlj;1Tk$#jh3vUYtBmiMs*Xqq%> z-q;`kaNA~3pLJ6Jx2-;nT&t1HwpYRI4^&^M{^O|CLSf_w5_+7>iaCh*`>OTYCjMF# zZcTmSCz)7>Zv=+=24%g z!|%Gf!`YzPBWtQw;jdTt>lFS{(S-g!5;)a5PqQ| zAR*V~nD~LX?mm9%SDyZw#i7afYt=fH8SR2VV3zVYp0I-pQCaK|LldSV(6nI$6DTLJ zyg|i8=>R3ynrGuU!wK@D29b?@v7%?+zd6DS3{LF(Hc3{duHb=86FH2Lg$pXcFh&ne z(3rAiKK+127z360!5EoR(MY08scK!;AhH^WE@0$+UlzOS^25G=@5jnAxO4&YsUM8k z`H}^5mVk?uZU03Q*`yhSpdySQP{3j%2)f49lqp7#1{7VY%v-xo`xdd=F`SQ9K7DkV zzM->MzU=$=$r-jl?R$STf{hFIeKCs^PGGR_yM!2H-@8OU$Bm=1Vc!R77isk1q(Tfk z5ili934shX{4hoqR$Tl*1&5sqQ0Vy0gu2-N9+0XlmU3VN1~4=v0TD$OG(1q@!xLYa zJ`e$ft=jE&Pb>|dXX7{nPZEq zwjlJZHUYeA{2l{!yFPUNcV-~=sP1|og9&qqi$TV$`B!p=s}9`c+B; z6ny(i=n&JB#R4mnU0=vaNDHVIRgy%1rCGVxdi9$7WO-C~Ih+v!bBUM9!X&?@JleTp zF418^;Wy$s2VgQ+rV$^(lG*l?C|OcMf9exc)CQ8$K$X{=TKk|*66M*D1}i9 zWEolFi7YQ*&Nwk+x)@nhF@}sbm{>9WbB$K*L=WtyFKYTHSnB{pio?~ek7ieWg58w< z>Dg}=qGr#cPid?trdA!KpbZ6!zb4RM}RSNxq zf@6A>x>d1jrp(oCIxm%9oqjL%Gj5XT1}V~9ikz4pZsr>Kczqvl(=f$eZG%8V{Vh{yy>1G652jZNIGeI`~ZGH zfxq!Z*GOGgDc07&QV}MMnZXZgo-Z7#yG`^uQJsC#SGGSrUn4zh`-{C(uboZ*n|1w? z@%&QVs+Zp;p)UmOQ*GiNE}LWw;>b;KF?@06$Qf6Mzse_W<7PgAZBisEg$O}a?_m_Bi* zkdf1fi(+l6OO8JPMFq>WN`zt7C9lci{C@bjJaV-y2o1GO0Ca;$Xd44{DCFr>0SU8-{(6*vnua(?wt(`xs0EF^AZSyvcL^JA5Fv$MvQw zb(`)}wNcxj-pm1dsLzW8s5+@iLO*B|w`sf3m2#VIQ;0R%9BzOZi#RnA$aDB{%|JDr zt;*!~wQEfLb;|$Ar&g@lq5{^Zr1O!e5AVOXd7JEWKFP$SOxuXi{^pHnfAg}x(MM1+ zZFKWF`pEz0kM7GbRS?(tD2eG4gy|rj!|%fbSc&VZiAN24*e7l5S)brbpBYE$`f20? z+|SXr@o!Jf1NhrUZOi#0ww$+V+xWJpW|5q~{Y@X05Q7y{o^V2Iw=;9JZPYd*v$uVb z+1oS{l+n%GJQD3^U&Q8f-sY)EO|dBFL!f4kMuIZ(w>?q}Y0{WT{wwjlH(wq4;Mw888G@E*ZYdAPKhi1F!;2q0Dd$K$$ z*gcO^s1>|8ziK{m6kVY^zFttEIKV$m=?@W72-rcA%>(=+LP7>0kVF!&5kLZ?1|kR~(Ggh8d-^!h z14Uf%wMFERBe}2WyrqvJNN{dRr#|=qgd_Ok8)O21L7MY&-Ys=Pgj@k2$shm|xanX5 z6sSNF3XmPln*6Z9tceAJkV81I<67WH2NoDX@VyR5Aw*;cNjXaJ05pLJe4pOD7r%My<29mO>@Mz%xyEbFZiBcH6J;OuJD!;Y||u%RN%ysIViz|4Tet0 zKV~QR=y8Ep51|X_FaXjV))jzd3}irwP6MJYNCS?q{i99S+7? zXahVrF!HE?14HxxIvOu_A>|4xupiYx6yzfw5+HpN008OY9Xa;hfy?2@AsoOv`z~og zN0N>lN%fXFHVzU5N(R5@(?fQUw6k}b2`q-`;~RtdR3<<|D8OJ<201IxhW3M>KJ;&zmx87QAaBF$N-a!(%4|%Qi-dqJFQ3d3Xx?R`H zW306dA2^{M$B{&yv%3vrg2t<*Vz0MbYpoPtTw+U*8 zBEPj(d~Kf`47$N##|knB>VIsaTb&3Scq&)NM-b$74TbI$Lum~1wa z#b7yz2m|ySeB^|7gvfB=D%WGAbVz5@KLaK)f!3x= zN3exJ6@+x-lzmI8We2t5LInGkRLqVaH}P|J7~l#)noZ4t!1k|RNv*KX>|0`h6B@nD zu|-XzKlp9V?O%t+l+oeC=3~?VM-qK8MFyikeHLLsdMoNcdL$KG^kfZ1dhdx@%2`CQp*yjMY z@0cKj?G%R}x1)#-Qpnx;MGm|e)5P_3kVG{LpXHC!1k{p=m}LHM}FUuT9pyC zz5KCpa6l4$kj9fHdO!$47@|iWBdh1yAQ%RB2;Mw^FQV|!1o#MGB?1?)>l_^g;A=D#WWC) zebpxg+y1Fz^W1FvvdJK=Mzw;h7~r!d027tcAJ-pe-VePZn!~yp#fuWg##Q(&{#&a# z&>wu{TL58%7UmMq$`tdymq$C4Fqcp&%&VbnA5D!YVAYNh**@M;WO2BNdd@5I$`I5> zXq6HDDT=~C&>_D~)rsn=lPlE85ZjtrPv%+MPQb`c>~%1Q`vmtB{n53lsmY;4>T}jE zK`f5vi(Knlk&BwRo@Y#W(l+?ufA5t?>iz0@?|ESsi?dZKO{Ra=Dr3a#+QX(+TS#rO zjyzoClUA{L?`a#6nty!}@<)v{KKU<=1Z6ZnsfEa|(NyDFWn1q-64K-&pX2ZIKo9&{ ztEZ3D5bR$M1i|lV{af#g_4~X^1Qt&Gy|N}jVsZ9)Y{+hlwx`dc?S1``EB>AoV*i&=V zm%5U&tpSq`^eJvJ^4wd2lGZE;*$@B|A>6?u{Ih%>!bW* zNX2KtmwZyJ5wQLKmPl|Tc+Q&HZmY0jZAEqCa<-G$S7Ltz5~ysy$|L)w3J*JTNu|Py z%M>|+Fqh~MVUoXdCD$j*dSx-#HL*A)tkAx~xM03Fe^T_Vz~RSjazzyRhyC(2%N5KM zn_R(cg&{+;RaQ>i?9+a+Sz6YN@0uvh5Zk9aX?n_kI+dthT`J42?^9O0x)WZVjAzOI zbS>YyVOK}9#5DW!Mroq`d7r54`ZubKU2m03b*pUtykG9s#kyp6{hO6VRL(wc8N97W{T3}WLGRjYAWYX>;$H={fVpU<0~z&z+$i#-rDuVXijgZ^QWieWXZ{{ z9+ao3oj<)QQapcpQ}sP6F;s;6^tyOh|EE{R(<=Y;w(5U7F=Kp9KBlip|M^Mzo_77B zzAC#un46yLmBm_Oaw@OdDM?LTt-JMfVyum`n3}vQ@9In}+nU5a7a6eupID+4(lpK3L_tPhVkWs%>9eoc-73?PqB6 z5tNbsou|IzKZJ)nApyPC@44U6K!E;lpBegtwMen;PeH~u!H*0)MStwAOyap7PyaS- z!@2~c+iQI^g6Be@CJ8&L_0+t*Ed**B@tiI4oTcUwl+jJ^v|gegsqXxZVojiBQqxvM z2kCaws-E}xvo6_+bdRQ<^U*b`Y5P;t=Gv)Fnbmx4OW~C!O&Trp^^ys+OsFeFrAsi% zb3MT1-&OYUm3=&gsocmeT~f2GSGFRa*P&+62Xd%w{z=>QS+DR^iK(*K7k#!xD$>!( z4rK58#GUo)CSR;sRjX#ztk4CL2_Li%+8nU#gH<-@UfH0Z0?P(vS)H5qT{i@ou$pYp z>1{pPp!36uBE<%IM{N5bmAk|D;O_9la^3d?x^h^n{o`=ohm~#N_k5CRdH(j{-+Frf zNauO9EqrS7e3H4dI3>3``#wE6PpR$BW>_>wY}?2+D}( zdmhL4=%X`y4``?Zi&y|UPoK1n}({tW2tJ50;fD@%_d-!=j?OvL;f#c=X)N?i05zh zk8IUOx9`zM_Db6=ofUO;`_pEXp{CBCR_7^M^FH*)-=p%k?$&|$_q6hSGTXk6(z9Gv zo=9-tnQZgd`6Sck{zpB3(??K7I9}(KjC5|VqobqqI(mtZMsg+`+LKJr(r1p^QQFbk zpPb27d9bB?Wn1uSTkr(QRPpN|Y3r1t8d|rS z!V;J%Q*7E%pe$LO{VeHVl*L_ruPn}racNLWgH`U;whzma@zt)>+SZGj^02NhcRhLu z($#tmM%kSGS`F+1MlEfanJBHH{LBA8FIJgSQ_sCN|8;)Hjf|zX{V$h1xAcuSq9VNH zIT$k5Ctea_x4%wF&2Oxv5G4CNvg_YUYKlJIN=)TBYyXHX0;fPKFbb3+$D|yKK^ZSu zeAyUm>LrUPAISG%VPxC)vuzXNy?v{bG7v9_4gf4mKEYk|o~vJb98up0kRV>c_h_L` zVIhW-5pem`kS)cyY?*Ubx1g~FY1U6cn)Avr^8(CbfUu4Bpu{gSM%oL#p7&>6#1(w-C z7c5$UDFO#5t}yF=eH@PR_YEztAGgT`v*m_{YWusP!ge>Z*#5OQr2NjlSb(%P{WB*y z&Co*P?f2#K6G4b#O4An!hSYhSIk+h*b9I2tt9axTr@cfap>mkN=M zGegzO1(bDPVC!XK#YWa^2$m%g*ue6c<#8Nmw{p`kUC{VU;U`s0a62LJb;RV6sgbQHX3K#^@yslswzi$_x`T41tB2C?3c;n_8Jc z!Nn!lY-*K;nUIY%#DG+!@x_aMf{0kq6F1Z_cp?Vz0y8!XxS;WHLP|#kPTa5qBt`=Y znqVSlf+ljn@dJiV0w#j+0RSeHdUl*~lhdMv1vo7^lsdL>6Cg+GOIY&f|JyiIY3YoTPm@Z2D1QMIbHk*dwg2q^eOBQ38Y{8~sxHyGLWZ0%* zxOjjxV~ZQ)mKR#KL@}b-QbmO=H`MU3#RV*A#w=2hab?A;i42_Qgnr%cVV#q9UY!=CwU#W^w{ESM~Jh!A1U3cqmvz=TY zEitXGYKWo+qCdFAHwZru-N6Cr)MnSS#a+LJ^rsHdAKMMg!KvNQuE_O&)ZS($!x3?5 zGg+(#yTIaRviz#mJpHMWKqRP*qAR@j-aC_B2Q3b~_uhLweDA#ySlmo@*0#@N=WW~C z<9j_%-+S-9_qx6J-s|=;zW3gHdunV(J*It|CDt1KAX1*XV|C8izLZi*ZYHD?tjg(SKX)c@bUa#RhlZ7{6 z&D}p7FUNLolvY}Uq;3t0;tzlxyqw!hqu1N{XkadM;SgyfSyNv;@((PZ(x~(dcV$Hj z6{-ON00000gB1WE7!V8yg@U0-9OkK9a}N{%3~i!5W?C|pM?*P`!ytx&7>HtwF@z99 zkTFIXrfRML96~6-r-&VfPLW3!t$RegGrmHDfi4_Wk!RnB8rXt@MIBxy2td}#Me*Z? zBa8oMl_Q5@Cv!2*;E2VR*!op(V;vbP zM13*Jm*xU;s^dK?lAgoc@Ri+NZ2zDb@ctIU$U|W9i-7GwvCLvod}K&8kiGYCQX>&s z=1oySFI8cq+}=-VU0e^pxZ^3`;zfaG6IxKZKJ38niU)D4%Jb@88M7<(dr_LoV`u(2 zY+{&0KsLuqo)Gh7WV$X*J&p2HTIy(h%4TP`!v-;^lU=#Ob=P-v;&C%{k0ie(g2u;K zkeZQ5MjDSrhRN|*;1+#9jq{Y2>7iD!+}~N!Pp4yINha9`Vj)TGN6@6jh`L0RE5%{N z2YZL~E78&q?sX?0w4lEqFzN&|zD;gFc%!$;SrAU|Hpv%4emB&Z5i#8Kd#{G+7Blf3 zF-d=`Ck;0F_Bq?6u2wsO1OSO%Bi=FOcZo@|O_GR1pU)x5JTnP5DYO*qvFT;+vjqBlh_3>Uv#$R{cO&j)XSKWDluIg3#!Q zj}p;`j|>i~xA2jQT~NN)(P$M?QKAf_QCc2_dA2AO`DxK%xy*d91sajiqrE_)k>_yT z@?>Nue8purtUjt(3^3v(LgyqrxFW z$jr}u19S8ucu1a0O`O)zd}Ieo1kB1nc4lh00^4_WD7 zyY+@3yic~Yn>=^B0casbW3RHGmM_S^Xk!W?=!6^p{0?+~?(CdRojA~TH z#HW}YIV2zH0JiW12 zYE*uY#!=&|edq^C5c-2UUPAKAZS?BLWI01ynPuvgmD;A`o#~n`?L;Ky4e(fDruM0Z zczNBbcXK^((DUWwQJz{=L!k!A&$%{y!Jwg9-tmTzI4_!a2Cp9@A7vZO(v)ug<_4_- zQ{C>2s^UB=VD)2hZ)!OXyJ81ce7Kac7#yk4Sy=Xf%R2EBm#hvgL4PIGs*E5kj%@fS zPfcg+d)5QJz*{&l?(zo&N=ho3s!Pe_v9If9#Vl-sCERVL>iyct|F4HV%-` z<^tnPrZQsS=iqg!&+1bg^FgO~x)kIH%r7x!&`e!Do7N|~oFmYg>T77r{(Mt?F7aZn z@qti&PaSd?Z9N6g#@pkjEyPY|6ZxKOlCn-?E_6-n!Wxd_{59(Hl6)=SC1nwq0Mdw^4T>DDAoyh>50z^8Nhe+6zb64qp!J z_!@Bq*o{gOMp!i$YuD=5X}` zBVy2rG%7sZs=yXQJag%O%6$WWc+gEP?!toXN@n=OEq%3-Ld`E&VImSuDdEdmKcEj!`TXuKdt)<=W_tbB;k<615kOMg)w zFTlZ$m^oJ7lS1K7ray5YP-xWBlc4RY2eoS?Je5tXTbt6OZQO^~eVXr^r=d~++lPJq zHhz-D=p5VrzFnfZE4CsQNP!JytW?WlS5W^n)oN7%f*$bP*oH6|R2|<;#asCojX!H^ zE4AuXWW_b#YI#wBXRmVZb%pUf69zaxSHl(J%7O{<8b^72vEKOOD4}u8*(ZR1<_YJX z-G}s+iZIfgbtbT9j-d(Z9%e}3^CcqNU2I`k7k+9mC|H8t;3l2*H^<*VU>mGSo1o3y zFK@8=v!a}JA?H>kqaf0)Q9(ao{%G%Ukt_sKkyk5w9iXs~n!RvJ>A8{b9k3dEk;IbR;Fw?` zPnhfmAL@1-nqP*A8ucrdG1rxfWyS571;mM3W-X+dA0S;|wS_|!-ehbLEAa}oH+ohg z0duGvv}j7SpFMGJSTzwr?ZCLKBJc3gF+guK5U*uzP(tEk^h0!XY{}Lm31hkt1_dBY z5XMrrf7+Fi&~8!D1o^mzn!btylL=f_C(;D?0jyjUbu^P>joaU5Mem&&m! zzA%K@RRQG)XwhUgxH1vmM>GL_3(K+7ZrF~1Cq$R?kOaNnHF58FA7I*b)*2PzEyTaB zj=yEKJ6VmTqwQliWJl@ulmwSt#_4=qa^*EkT+KFsi>wTo2vn~b0LKDjpmY6wyBw}W zlSRJ=Ac}p?uvyUs=+vm#SVRN4vsKK& zYt3gUB}A~ZdX{vRbIe&xIJ+n37~&1G$>XXrEI|BXd05njlU*K&X4a1RU1l`{`9k>0cVofty5OP++Cza`nK+E!w zVvgvCfqd32`aGoCYbarH6&cT>Djz#7c_~6Ctmu^-Dn-D}ygu%K(zm+Q-G( zXnKo^q3sAU8I7s`l1>{hW=fZgrdO$8^{2?@Fv)F-cV-1#wVC;f=4H`LKm->W7LbE% zaZaHIIT=fs!=Obu$rk4*Xi*Nv7UmFIkW;aRIS6W$lPqx#f*#~(EJ048MLEk7J@zGVsEkr6Ft*Gy@QWijGGq01u8n(V8pyh9Xxs_2lWarZm~B}f{&j0pg6(BE!IuS z-~e^KWPq!UVo|58uV!6LN~EYRWSsvNS((LCyHVh1xCjq`%yGzN6 z0$!vcex6rL5Z#O&=KEN@sFi>OD-N@5oVa?3M>Q`D*SW}G3>z(+nx^n(08^c!MFPD2 zSFH{poxQ1qk0Vi)k*Da~rhK+P>sNL!+LeGY5nam9&mYR28Ny zBuy-JM%?=biL{gPk-QZ+(3a#pb3`b;A0VbM8WLCCtrZs%Jk)O^y73|PFBXkCwjP|B z9m7*QX1pCMBXOBEC|dbMC`d#Vk=_dAjT|35U?;|t^3v|%jsHK2Ma1D#Eb0duhCXkku~Y3?9gw1=gsJTE-F@`#CYXdy71TiLGcMp2`8yyHk-i)AtpXG9mt&T%jLVkGT zgD3-#MW)_g2N;24C=)1@P=j~tKn%h~P!y#=>;Cl|caK|15S$Ob13(9V0tYKP?2Dm4 zkO3s>)}i#x*U=tvh3I4kgLY{2OQ6!1dm<4g1R^VplqZdh>2TTKA7=|)e(UB9s_*(b)+hIsKJgD0iyJvpcSxg9>$k6 z*b}!&@ZhnDj)bT%Kli_;B7bnpXOh6=P8ofyjJP88lBvHv9HLAW*MV_yN19CCr<3Fw z&YRq#5&Q7y1%LEM6sdvfFI+NksF^IzjIq%L@zUfw_nmLZ7^H1}AJWA&0(~u9{UKM& z3ElrZg#Et)PSA5$n9Cc@7zTjawn9Nc^dkP$C7S&l4huijhyn=U0tKb}y1v zGgB)!%$P4)zKMIs5%!}9Djuwudi)7Rz`XXf1T(?d^jq>8;F-2yi_?2PES^CSB!+3P z4I-a~XzWT?u5cS8j5fh)60M8?yAIRfb~#$71k6*7LNOHXcfx5pUa>UyjtTDawXtjwn^HK& zCU!hu8C@|OU&!i`eO(Q;h(yJ~+Jne*L zAIH@hVMimIZ<6m^NN=<6j?&uQm*Z-Mg9BgRwoDuSW&)YjSf0nq@J0>jAQY-@!V2W`P3=x}L2)2>G z78^gXC*Ewlnngqp``!Dn-K4mzzKo-d2*Yv{D?y8q#jUxH8V4DlRSW_eJ`BSAL@t2{ z3@`qo?5M^QzvwC`tX8fJi+ zVrg)WX2)HcZ`{_280iOXo(*x@8k|MYOM}|n?IIL_F)5U#3Dt$r>Ig|e-%2)m3rqoq zrH0xP`-!$QG^+VhNXk8+6<`B}EV|FV6L&-dtj%wP2D(0M{gOK4aCoh{Vee#2f(C$z zyAu;i2?WeziKP9VcE@q3gS_f|U|>jG6l`1p!^9RSaX6#?fRkFxXKJ1(jVyntsI+*B zlu|qQoxh$~A+`6<+#CJ?{VZQtp=5c|0}x1tkWeBH3$S(@%b~LNA80yNDS9anW;l%e z9UXd`Q*dg^-NWi#4SkN4s^Ml&^R3b`A^t$OP(0j{y&e}W{@fIHsw!9FSg+`n0nj!{ z;uH|~65@5LKRmc{Fc2=Y(Pe8J657O=pd#=~!SoO7>C?XlN*7=-?TWUd-jo;v--x0S zS~u;v@=au?^f(?5RfnUx3a_?a-6t1SlP8_!;;rbG+Mvk>C~v;LuySY|^PR@P^Z_6Z zEgw_h68wealn9%sk=x;Xh z5pf15&T@$!(eTFun-Ht-1wbDgHK_loNe0iq`A zd@!MN@?=Pwz$h}l3hEzQiZGy7OtkOMo{SDASGsOav@#j78ys??O=P3oqlfbAu0Z`F z+s*)`zNsuO;#B)UMp6?r;$Md^P6&Y3P*TUbw;pjPaDZno7%A!_x}y-&Zz6sbdwMjg zmq;SaPd6YHC@_Vi(n*~HQQ6xDB&IZzHlQX7EF%DWzY<%P< z8f%xtaGBZ8&)RoXj&6)DTs=WqJlcDg#I(i?b`>6FR-xkcI?K0OcGs@Lv?kYP7F~l} zGN>U$RB+H@X|e0jg@@7$M{0(XF=(K1hFv>ovgMCq{=}na?{oO0ivJhYCx+HTMVW0=A$|*yvN;vVf2;S**4oZ>JYl77@zNM2P833fCRsWl>i~_#m9j#N znx$6#Rt@{Mj^Ec!Zm)z*AE)T0(DQH5Q4)t0Lu9n?4nPE|_$-GXhLVXZa7xMEzq4Qj0DZggvF zDTVR~iWoAmAf#u`=`v*NH?|4;*%uXij{k_XoA?Mr(6w{wp*sB)I^^PI;{fON4)#^W z+EJ<<-b|V1!o}AaN}#Z@N;gfuoM1`@fAm<|4H_t`)~P7qpxp|(-rmBh*WqR}DW;N= z6-^2RC6LfhBwi+Yf|rb8x>f6U+nDIZeu9`^^r|ZFuZ=Agrlj>an0~5O^j!1bI85i( z_EcHtaVJUxNrb#D_H=f8q7n-3rM7)0@}F4Ar%^>;u9xfc0^gd-HpC)%aIhQ`?WheC z{jja6Df`CyHVK9})@CpL8*yt=4#=guCG^6Nl4Osct2XtDh5|RWHYqF}CKs;SWQd&e z1?p4QSS}C9Yy{KwO*+pWqKxtKSn)9liMLFp6KU0n;#hcMVPXo#)DPH?qSWtlXlEoN4jFqUCUA#;y-KyD zZ)eY?)3&X_3i*+M`hW6EZ;3dmG2F9p@g@fTjTee^O0kGfivIYDae^d;MW^HuBBZQd z=+Cv_d`yl<#u#{z%>r`A)$dwnnlvSQln8pl4ZK_t#4xxcj%%HVR29 zQ0c}XG*THNQA_4}5mb=j0_%}P=oy|`CA>D5t$_#VipU)t^&de)Se{BS(sed2tl;9# zTcnK)*14J4$aUi}&7aza#6FPZV215gbLYK~IUXt4qELARmXmxMJ4faLBJbBZV%i}E z%(nD+i|RfN=XHg00zxgoC@`sFJqZP~su48p7zlJ1(6EfyqYf0k8(<}Q`q0$;$i#li z;VLg=Xnh|8|oX~tA^yRF$xN)E!G0$kFgw^u16DtA} zNM6qNAz0jnDEg(n4a#jK7hBqg?ACuon`AxD@(MU}YZ%!OH53q~Z&averyx#ny5n{r z?Bjq@Bbjb!cN?;*;}AV$3fKodW~n7=@oIbU%9vEio?I%1s%#ib_lCe4?v}Be6ZGL# zPiQ}KeECF35ZD$iPKY%Qu(7^#1Hc0W&JzOJQq$(z850^D4;6xt6Q}xjvcX8lg-uJw zFd<|{2Ny&G`?5zUEZq2|SSt5FgSxaAEn+UHz=X?o`)utXCe3y51i}RZ zEFrjk$&)%_K<2y%sIk=RwOuT^_-M&QK>YV`i_XCvKv4x#h{sJMO~c7QiEcK~^1Jhp ztFaSt*qud3;bOc!7D?9)^;1I*&EhJ6IiNh7kEXp(ifE$}2-rUHXM1L|aZx}0qJ%V? z6oOBWh9Ott6TvSmQWWnSW>;Hfg5l#zyw4@MjM%Qka+n88W)Pc(9WjDj)Sk%b^2_P` zJY^5#vUzFbx>dWV`fEP|>1X%i%X#JdC^Mz*G4g5SzJG#_R%3GBl377yPYkQs``|Wv ze*=iekz^u#o$vTiKeo6XQs05d(K1+}_ul8?aP0uf0f!aap~gi;E&iaTMg-8a3c_`t zLJ}}Otlp5H1j*z2McUH@;K1O$Bf$kY=EFgB(iHNx=gSR^g%nM7WwAJT;!yn*U~D;K zG+y{cB3z4$fsQv@Z$y{(7#VlqBJ7XWB_D3-)%@=kcWYGNIe$cm3vVge52}2`>k;XG9$gdZ zC;A`Q!C^;4izLmvt>r0}mXH8Kl^PN5lj)?$1%F}=>46gtxmW|&=eng8e%Yu4Dbx`} z|2~Z-uylP_@>Q$C1j8FIzY>LO|F`fd`KU&ZuU(&KdKp5L{S;4_WMU<{LCOn^;I7Hh zB{#Veic|aaccHs;4>l&51CZw34^778X^W4cx2E*CaBZl&QEx=q4IN3asiUs*>mIqn zd}gff)?o0ymXpSZW?Mq_Aie%(TUP7%R_l#YV!bN*GTn!*Ruj9ln}KfT21ott1 zpa9K6o9xtLyqLIW6;gqg!_o8JagD8|eXBh$KS3k%m4 z?yvZTRQTV{EXKCQDcVvsnQKVXZze#M1v{Ib?MWu4BMBKGaL@-HZ^6uBHHmnrLHxRd z{|HT@LJyyT5iWV@`C%XSiqKir!5BbQFDmI%St%V3KpAi z5nIqT*=O#3%)R7X7VBYqy+RxAAZTZoE9|brvRFZi*@`4cO}mWnID<*L*rz-lWoY4# zax3vfDi=6GT!!ruv3h_wx&AExo6;gv9r$42oX|Q?0NuNERr-AzY0%vY_|eiTciox0 zJJ03a1wvZq2UreQ^0634Z(*6hl!uk0A}k&)g$riC@$T$a1tRpZRmP78A& ziWY$e`H5MI&8sbC&Ao+j-&t~uJbK;oeeFNcW3doqsDP~+$wes zVWY72M0p|JIQxnEw;0Tb6!^27xFV^+={`WfB;X%7-Sm(R0r7LBwjQP=zoK4&5a~ks}8Z@s;}E>hL~L(%pMyNK&H%o+~{Y-ZKVs2 ztDE3}!XE^L_F&8F?g%JaEwM;E;OA9y+B^V%@5I1^wYC@-M*Ru@^Qk2Lfn5^(abr+< znkb5#w54aY(tAsG+>HQJ8PHZQL>W|rs6!e0NQb#Ga}bBvm_Gj`(r%8D{6@UtqbzeH z7#{)x=5FF!b3~5$NnR7pL;_l5+YmR@$59&s;24j^WpW^N8(Aes0*?Df;aLu5X1meF zTb)#07sJGbDk4x>@xtXhi|`AT#iENcyCECusbe*!Eg*gWzTotvH<_e5?W2-P({uVf zG=XkzJm?*S?3#eXp=(W)YX_Nj^)UgY4j4%>V(v!PETr@{H;Z&$>Tr%kcj48O&Gv_r zn|{0(oqG!&>h_gd_Y$=;*G6=7@yn+vk;EVfvzM?zN>!2NZ?TiD@jEFr} zKX+gujO@MpZ;2i*cSvVMa>j7(-D{hFJ%aLL2{crj6yF}`!hxy#C^#eNd;Ec*`8<*$ zgfmFMM{F@WO({AMAYiH*Ss<8Jvj(eH0L~KSJ&@)-->*BS^ek$oeG4^OXx>;>h#Nj~ z!AIQLj#+K1?q>PSHagcmSq&M5l4TYs-mmd5A6r7&&A|n0Z3R~FwJ5)tYViB6o{X>> zGT}jYgox&;ldGtgrSqulD!-FDsD<*cWLdoM2k6#)4Q$O~A-nm(=M5`nM6mh0tfJ-Q zk?cyL7h-ewN>a;#S0RoOEE%@jb!+pc_5-fdUkR*FS2Ws{AD6A@l^F=mgws}Ozqfw$ z6!x3;i2UiMbX^i)$o>HPP+C$!ptwI83jQU&KQh^r4iFtkubcfSe7P%leI0 zdV=AqXY~+wbL(6m00ug)Z}u2<(Pcw?PVvl<0+31mzLtS0zte1fz=lrG?s7@d?pl1L z7r=kXbR1GZ%*9~Z$}UsNigYJ8lI*C4{E(=zorTDdRxc#YV%InL)1@7)ebW7Y@Dz-; zLMui@kpa3SX(l=^mS=z8Mzin(;&4&tl$!&a%Q?F1*Cl744GE3Z_u(@es0>K?6oDy2 zN!Wv*^vaO@-)t#4OO8f9o0ZSBcqw@-_`{OqE-EWJ4Ice7flka~Q5ayG>2~X=d>PFPV6|18*v=oqSY|(imNA1p}vc}t77R)QL|d4+v6-QcI#3ysMQ z9UJ1B+#g)+xYzn3DGUZT#Fp;3OhPXxh+JIR0;Df@>Q{3-PFJ3TUWwzBi@>(+jzmu2 ze=tLGEc0N9ar-K+(CshB0Do^DjEPnMR~Q0`8`V#yG;@%xX_P8b#y0Ah8dvGj(b zCXqsi+KJ}_1Zz}JX>SHD5LBH+d^qs`Sg#(agSMcO^nHbWe5Sj|FNCzE_HyGlf>`Tn z#7+@=WgbWa=1Hd47`>wDHH6)L!$-7q`Jp9;^=~0>&mq$L9$c8|ZvQk5GAbe{T#x{iND5qy1BKO=kKpS!-9y>1|>vmM>NKT6+9zKiy}yJ(wlApCgvwGHd& z>X7*j^}G?L>|L3TwvY6?shm#`NZRC2tV~d_jn;ZTEu6ps#oC%Xt_-B$tn;h814@qj ziD4iPMYmgYgDh@4j(*x~XNKhiT{)%+xS`?vStNpPx;XYN_+5{`tY7PSOYm)@|2vS1 zpsc!(zrI!{Az`G}t~fCZDz40+S3+!7LCJo@U+~1;qm>P32h^l2TpdW$vf~QA6VrQ$ ziim<=l{+$zJpZu|1DZI+kFx@GCpbs{i%$qN-!Tg;Gu%H@m*W_vX~!{_d+#(4`GsnJ z8W4O|y(KPY-H`r#N%pk7ztbgnXiRbgf3D&bj_hnnAW**BotxFm)&0T--(~zTa#cIDgQI zkGy7^D(KI){t+$fuWd=U(}zR?XVnn1{UMq3*ji^Bh~^29Dd}*;dm-R2(HuG#RH<%& z*KgQwp1rb(;rdb0aOyZWHNLEn0KnG;gV;*fHRQ30OfLnMDx#tJ3%ujAkX!QBDJ`J^ z)L*RV(lW|;QMTG0e&r!j1JV=lusJPs*4T?XOi|)}5!e2lXH)d9N(-TMzE>Xg5v!4No$g{3P z^nk$W;<5#7NnJaK8y6L( z10%3bQc&Qn)%ZqH2SZv%z*oqHNx!PuGkeG`H>n$mWw&Ts_B!=SMOqOpRydl5Y{z*Q40!%=anC>kV8oL z3|gc0I>%H+I)R}9aVqIW)Vcx#n2q1^Btppfc zvN>+qnxsSTp1HKhTAQG`ZZq@z#g?l_(^|dT0DM4$zrx3mU*}|VUFlkmwr7St7nA~V z_^*s7O)MEfA-Xz3AW>CrU1|o3dpM>{vzjkN9+)WHyTDAYuk*}sIbc#La1}sw+$4F( zMm8?Db$=3I+P6a-u{M@Z=(sJn`4{&#>4H*McVT|bQT?;CX`dr>XIrESiBd6^)=&}d^x z_|`(N6mM0r4D@X%#Br^rK9BH6J&vW3#>cBbiY`2rj^FbIqceX(U^n;6s6rj|PypRU z#Tpqncqnfd1o1$Q_a$VC>vCrx|NQ*dX0g9nsAq#^ z9N3=)k^%uv^hYn7t&uSRLWA#zjxQq0;tkliKIH!inp~YhF9v#Oz#T_$Qq-&W{)I{w z2meDh^guE)Z6igrF0Mz`2^MG!24N^7X|8kK0;;_!Isd$eVVZFQmpb#iy!viv6TMoY z0@GQa_7`(RU%a%OWZWO7^cEW1c#LrSZ+&W;fWJ03m?}4E>@B*!WJqrHbTC7FX6V|) z1ky)~dvynr%oQ?ZpyXReI9JI=G7h$8c1~k z)-&sLe@E(t&&_1S^mhHP>Dvm^JU~AN+N!*bCZa*D%`vfDRPY*SjYD}a0)(0YiV{>rbnH|bO)@MaaL3ha1SMnzaU>J?;s&y(o26Vo`58!M)p(H(Mw$RpzZdOcBgW#3`ncYgUSsE?s!0hWNhZZBHJU z@2Ya`$|{_v)fA_!Woqv9qtD&(Fc?zNJwQi=y`+^z&b*MRB5ET^~q{{8rQ3npQ z4D*Z-I_$O}+SGr8cB(z9b~MBZQHCv7^`riTUzP=Nb9q%;-a($?2kQDrTXRd;Ifz>4 z|36ngilArtGL4&s@N4?XaWGSkL^hQY#iNaqC@o+inT?1rtztZN#In7uzh03iSQ&Nq zFK_l2(V*-f*4dozd}tzDxeUTxdjX?hmuip-nD>_ehTOL6g*^*~oK;D)65*B|(Y9vM zSaSJR(!Q?GAH(wbMa-+KSZpAQdaLeg;29?2#B&!?P#7o8;ipu24qbH`d%Z8z!kMGi zL<@qYu?iNRg-3XMewCvk<|X)BvQxgBE;WmmML8KNY@6@?zJQE6*CCA;Q^r6N_urphQ0 zv*U)~_7+7cWN_6gih46I^1?#N=>HWJwfgdS+r(^x9O zm|S9Z#?fC>kYjJ}ubvWb{Bon&_Mav{rCAPU_y~SxRmbo>qU5S#<+b_-kdDDc4W2wb zJ6UL4{|If153O1llaKPjO8-MD{B8I-u>F0uA_x)zO;VVXkl1ov2+Lcq^6w1|BVVvw zpUF*&UFvzi$noecOYG zZIscnU^l23mV!;etMLpSf<9Bfk>+*c+aCdsud=^^fb%p#5Zj#CIi7#;NsC-*QJXW0 zYdwzOI}ryww{LOcuZQWKzazNJ7Q+^FtS}*AlgY@?&vv&ncCzbVL`Ccy@y}9JM9CdV zMOaFFJ58tuaPFD5R^Oqvb{Z$%Mzzd9Su%wvtQXJsiZ0-j_s2J5iB8}a)9DP@?Z%{Kf;)g>|4F7;&03>Z2Mjxs}Ec0pL)cDO231x9MWOK$v|aRu5tC_gT`Y=VM{f=0;UsQ2l4#yjBfPL zC+6zerS6#^`b08%gl~Akzq)|lo@_D+ZXITu$28`d3mw?T^5m#R>2#}1glCBdCi^>; zx^0*={gHtye`~)Mr&owSx4t4deCE!hrXGE8`~meF^~DrO3%Ri55OY!*$1P9n+8J;>WPb}@up>lb#FQiDxUP9Kc+|ClUAM$v__ha8Nl5y3e}z+;6l!b zx=G9L<_J}>uE+Sf)6X5{5ms}DMVlmB%a|9oWRf;#*v2cf6+jtO1ZCPs_LqX1Rjm%H z+A0MbE$ag%(j8yjhxP=@2Q7mW8F!Ye4^dgg;Zi{QlJ0XO)b~jVZ9r-U1@#%rQO=(R z4*{s=NL1&2Gx;tM3BjTnzGZrf@fQ@qk&~oTGYXr!W6L7>AZ1M0Q^8i@AZE*q%TI+R z6?1DS{a@=JH!p|)%Nr6`m-;%P-d1=ZLPuu#Vx)V(>N!@Rp)w@c1IiT_3=WFkCxVr{ zSqxJhM2PdOCQYp^VgzWS8m}z6Yd(;ODAbYCLZ*gl&`rD-o;n<>+5f2gBr|s;j;jJ* zA?n*w0#ZKICauO=p7f=Lr4t*PS5U&`V;K5ZL^wVuCWw5X6nMbECH z5>gk$sg541O%w(EucOVsB)EIvdX~S7P60;m!KrUjk1oC%NcP>C=C&YcH}lf_{C037 zK-Rms%g^HG5T0N9;h6MhIl3C#Q`pdO_m#g*m^w&AtvWjcgR!b&iI;T&u{0-p5MM=m zp6uAYge|S=(tmkgNRoF#G`WD{5X$g;Shvj-%Mm@Hmz0!?@$i-Jf|tR_p0HLih#m(~ z!t1SS9^^d^eE5>o|F$aA;_ZA|WR(F;45VzPI0nR$`OmgO;yp z>y*yhaS!HF9~Ig27!=_wt^5u@ zWbW>mMRBE|c5e`uaY~74P{oD5)U+ZPJ`6nqf%AxEhf%73&^b9C%@jwUAi1FeXj6)} zLsg%r3l{&@b#s0o(OU1VK+=XUOHys-U}?Wv zAE=R2(9y>4p+qvn#2Yjk#!>sKGXUEYJ1sCLm_F>z z`Po+QXkxS-K3s>^FLjL#RR4^&B%^XmiPy)xvNWMSN^AV)>b{@c__KyE37(0L0 zQQtTb77ZnTsG2Fc2OJplBAo*+gEx#xF}jmx%x!ERKb9%P!vqNh)~tpch9qyp!VM*6E7{(GbSSM?F!ATu4hpHA+O(J+Fm z2thdChawl0K<;c4B64W4HjdzPkWpA@Q(KPd5xqZs#|sQAx)+$m6hAMb06o!->Y2ym zIoufC3ozAgW$Zz{cVZ7Ep4|Gq;|}c_YP>IMMpaO*k66ueC&WTQ;~oVm%V^C5GHtkXdt zu6=gB4?`FT)Cz2;cTf@SIR>bp9GlyrS@T-s;_1rl2M9k8O1*vUy9<`hk8qx_^ZEdQ zn{!M`^S@+_0L93TSZ7nV?@E6Eq!Iv4;zTFi@6x6GW+HP85YGt3HWidDntbIN$BSX- zmV_$hN%^-dP3cQxbv^BHhOg_cTuBvSu4NG$_Y{{{EOTsiEVHM7mV%f(R(8eoVkVVz z!PIis>LoIABKw(@_~}PSixmRIo~H>Fe@KtL+7Ylm89G9i#YEKLIiwJ~s5B}+M7gwR zyP19HecsLai&lppbl7|_mPQ0gJf%;knwgYH(IQB|m~JEvdNKnxkQ2Mqaz}i}Ocw;1 zOF(ysHI^=TbScezxx_)B!w5z{hf#-jFw+$PqtVge<#GQ9pr{h$oZ+(1p$Zx@J99qz z!DE*(=RPKBTt8AL37n~ekjzoj*hu_DkC9$bmbX_%*Fri)C=g9GkK~=n^N`sVyn`fBRCoR(E%Z+4fd?Zq2 zNc3FWICy=+;VlZSg)HU*r}z}y=(dq*%9`wz6^kVTv4O#oD@u z-ry)domFM>KR-H?b16oCMZ^K}iYayKcAsDK`@Vya<5TMtHmu847EPA^A`L3*@gI!A z?S*|)yg@GK{9PaQp05ZkAkKPDRU)3xIT(Yc;Lry|H8UPbdr#7v3~T-!$7sdJ#!ZiU zKWHg0B0{QTua$_kb$EYCGfkS&HRm~OVRfvfqqkL)g*$3RLs0?X;|PSLZhyy%ZoVb$ zFZ_Zesut_rh8x(nelHsx@}cNS7`2ZiYT+~@^oDS)-NHL}L3Puz6$u8P6ApYaff<8$ zw|T9uzvDXE6vQ^7_nLBnyV*5n`FjeWBpB^HHi@rL2|5_QBSA< zrc;*H562lDV?G?K0U(5LFIDLiw9FW>t3l1z`pGkR_Zbf0yqi|+CCtc7$FT@lzK3TE zx3Ed~@lyugoNxTFs!G2tRhPtTb_F8=*Uc+~Fgu}^OR zhvusG*9z9`+O4?YduiKHHR)IDLy%`4&C11zAyOJ!mT%371D@MS3mqiod+-dzjOSHn zcByi!gYzU`&+d!^w(h;{vBSeeyN3d*c??BuTi=k;gVYy8K0^<@&HIzFrrQ45qRWc%EKxD72Tad&5dYV&r zJo$pZ45u$ zG7*fK50z~&{NUC^;H*NR@$oH*!kFn$+ZMwQw@&nDEu`qKHLRi4iPg2Zvz7H4BIwx;|pbKst{%=GHI=K)6>kdu6 z3?cQ-G`^fr&3jWQ8u@(O9K^QOL9f_u_Ca%);2lwwi94;T^DR-l>zH<+Mv4K1l=y-I z$UC81H~^YGTrvbpRH(P9N^J*DLShT8Eck(!ZQU{~dzr4@>0NA2QTWQD7z8{ofv^VK z3c+A=cWbm%pxFRHDn^}v&Ro)>l>0Toev`&kCcgdrswL!-= zU3|kfpiGVzwiTuWi7L4eABejE7CE%v8VyAeL}B!fOLt(y72RgN|L*tOill3nzUn?X zx{l0X=0fQXW{CVK5qt7*P|<3r+YL77)OVHR06vNB99bV|_O}1}YtE1tvTUh(6MDEf ziTkvAjtkhNgyK-vs6sd%^Wpt@HROdM{}N=MOWhCo1}T_fb%-TATIgPT+Zv$sR|yO#f500VAdo?mU$623e6csa(yx)Tswzm~ zt*Y4s?fL@<7qO=*s3dz)LdNf?Zc$IRQpN2y>xisNeLe$^biy4)W)>bIU zIGarr4Udh)$TnZz$8oaenFgpto3F=VGsKr?mx$=vt4INb#FvOy3E@P6)ykO415GT; z_dIJGH(#y{V>e62n$%9hA+GZpu^zkSN-RvXK2EqA;V(xxj%L~_BKkW>?lS(R+P)=B z2eD$M?P{U63sLsZnnT`Q(xGRVBeW3D+^w^8AQvXe{73iS%X_QIrvGR4_pTfVn~h zOq4yX0wN{t!SXXSKo+Mz88bp!?YcWD-|rZ0Q~<2m7SnaJU)Mg998i+W^p$WP)imvN zKtrS`GMxClBh2fwY@mP-vSNs_a<)AcMfCeoU|W_yTe_Rp&Wj4=C@ z4?BTE_|JR8w5wTEIm1kJ9Ei8d*r#dl1r+A0s<4~jIz`NAER(Z~d&}`a$a6x%9e%Z%Ly6XTdx&m3*=S zS&Xc?sukbruRyI)Ff_mEm}1+cwW_P?Z2DZ-t%K=N^OJGQ8C`GmF>at@p+`*R>6P#(hsm4y_ke?e*%wnz^f>&oy)I)G?Hh4+qF8|kd}kfX1RcH;qZ{|Y{v5~pq22?P_8`iO3G4oAW8~tc4DsLBYw^6Y%hSxdi%f?j#kK7MQsCE1PjBh+H{B-7foyJu*~a`!YZ4m5_3dF z2^i%*OB!cAHMC5a+ftC;w+N z*A3nJD6~Rp0`dOZauBmRNPIWI4-I z;Zu)OJVfzs>7?gc0T5Dgu>Uz!5W5n@yw?(}6A~-+3CAK8&zL}!KczJ}GDPf_)5{rl zuh0TjA2g#8OsZ0EBN&!zRVvE7&w4>+b;{2!E6@c1qIB*Fs$w)3S672}6vI6*j8N@0 zl<|eARAsLJ7T6UdIiYZoW2j5Q|J|mv$`D570?(FkUM4#4q6i6N>FLuD=OT9#dM1|Ji1DDp{Z>CeXP*nXTb8g;qiapVEo7k(YU+wTMAU_^B+hdcoh`o z56dHqYqt!4QtwHWHy0d#^OK6+HprM^1f{a1d}i8#_eI_SHa);@B#%Rw~@LjGmwhIL@AEG^y6+kQSDuKP!b)?4uqc zk%d$m1O~4zL=tmU7rEQkQKW)%o@S1fdV+(WrcFRykkVE2cyapw-r`i*_Fh)Ql;C@E zp16cEoE5~R+J`MoTbX@&fqFWe`JWCF@wgQV)E~Qbf=hnGJHwr$V{1* zGu0_J_bQIeyf>;2+8%n>gCC6VirtU;?>aq{Ww*A zW;V@}c@W>rK`Qv&5dyv}Exd?Dn5`f*-W8MT`_Tme%;ESmL?W<_ddxF($fL3RZ2`u@v{gww5yqGk)--G?44lG`ETJ7p0w zW6B_8;$)&c1yNFAp%>;UsFkEr9I$jZTCM+*YoqK0?tp`#Lp!^ds=VxZ)hW*6g?0;5 z^BGU?TvAOHZRAS;b}T4}4m%ZB)yke<${h@y)_bHj!eUxutsp^87nU6B(RAPsLi+1- zsZv*0Id&M?R&i4JJbL_ zuXv!>R8`lk9$WR-0KiwgJ`N@T9#slMTCYiOT8avK(F#>^b`^}B)q5Q%DvbXF``eb1 zY$>IbDajOt34jS~2|%J$mc4b5x>ILno3Cu6#2;nz+$$S@BIi0MW3KFWpHupGnm;RT zr27x%C=@L|g^Y8lGc(oRt=YQN5}zB;8pLX;hYBt{iy=Pjm6TGtbot|nu8c8uUW0!} zG0p<-J&t3HQ_2`67ca;W!vY!zArt{l5m;DsnBd0_M=WcnLX5*e>6hof+G@)UP@qKTCeD{EpAvyX8fT-!0=(^=F;Vhx$);erHYz zJ2Q98bxtmSyzy^;=GXGY<~ruMc{BSMos?3_ms0xkCf{AUoDxV%Ddoltt*ERcKYq*a zqErIkgsUW0xbdYx7S#LPj(hM#PKM}H6o+w7pzye`mr}z;zoTGiJ{N8`x2rM36YOdH zZpIkDgPe?97UnXp$A24toF6B1MgP9DxsmJO&3)Vuf68}m?if~70E7yXoakd4yXaN~ zk;q|)4+s&3>j@Md*Lx{7T)aJj(k}W^TyVX|HYqN+=ui?!-VY`59slKIrEYKC5~t1j;hvI~N_W43>?H~Y)-RWPmBR7j2MNtcul#GU za2Y|XZCie4M^N2`3W~mU3G?9iIYR4Fmt#S3gMs?OXD&GCPA0b8Tdl_c| z9@Brj<9qKto2_PpyyWt~ttgBpx%_V{3Zvgrc6ayE+`6FKMDm&2I=C6|%hTu5@Az(y zau(n*khizV=j;gT%D(c)2#w!{GPgs77JEG5<%;W~5H2y(WoBlU%r}?^=8WN9aX(tL zu1lqIB(r3OO*Ov6etmP5yl2jW4S>D4%w@rzc}swcc1|w8OD;?n**$=$u==H@==@cjuI z>e-p=fZX7AF~%5#5!YjsF+#{oTjH}$b!N!VT;zU;(B!u>yT7wDTd91HL{3S3ly5$l zi5PX6xy}iDaf|e5Aw`zoDnyP+$&E(UpXc7&}k zx~N;-PJY;{S%TA?9U~DyPgqGoP=JG}rDOz#5JCZqcsF{ngb#plyBHZd4mePdz+#M< z%L(vO1Lon|!321j0k8OSys!woN+9$2cNkLmvQAq%>5ZoSknY_W)+i$Hb5fmZr|Ylt zf87PQL*YUfT)rI&7k;(jPF6C%zhZM@FEYIsVGzB0!E9$%dZC!U$kuq(!+kEX!N&lNln9Muh#>U}${yxZ`xL1qAcr2@_pr;a z9GvcZt^qG1uN;zIITYEa+kKAH3x}gCM`vhIe~L5CMhF>>OhBf#g3<^ z;zZ^3z))$@ihzO*YDio?0;RGf<U^T%lPIq0EcQ(JM-oEQmmbz5Jpg#cF406drD% zV8@ctLCVG#+GU5NM~gV&iWp+>YX>X8!<2dic?Q1kuRp92nd$VXEm{*()bcV?qF`P* zJYCe~m(iBXFC#0LUVa%JU49uoxn1hA4n(*!F28gjBY~zD4ogWd9I(7_IC|kQ1ut4csgb-hbt#i}6e-{5F?$qHshm%F4-4Y>}KBYe0 zDW#OoIj8jK(A|NsY09`B7U4T8W?@iAkQ}!@b})-ho!+TB+^fp*d&}ps(0+Q=@8hGh zO7hPGO|-OEQ5RQ0NyP_}?#qNC46bkd@_-Lwmh&|HQhnGEK>h4HkXkKj+`{3y>9|vc zm!>tmX%>7e)h!*aS9vA3$35?HV5){25-xlk?$O)?m3o%gk$32QTn&(UApFQZ@T*&I z9r%b)-zNcLfyQ7M&@2@Z9oJt6k|fQ-VMGkANneLFOrTfK2TAMLiT=EQf#yP*r9?&K zHYa2NI<9|^_d_7P3fg|EXx-0!$OUaby?P&=A`RWLp+J*Y)T}8>T;|Ms!o4G;`#yFC z|0ju%pk_gi0lj+vBczeEK*PX$8{X6Ko&xW`isny)JGqnVxPj(B0pFJN3Io0K{z-9i zz14TA`%Yj&>wYc<#na7Eb8IRkIaXGbTsfY|Rda0Ys?UBDTKw;##ZC48-zk!ue{M*H zq=YF31g@bHe#prU5Uw3R zZ`_bQ!pJpb!VfulRbERRxpr_#WbcHrFaix2uIG}dPvpwM4fT^7iWuW^!Y(jc0S>Ml zE(xjy43h4R%dZ=ZZlxB-k@o-Gkk0nM<=A-S3~`^ssq7C^&bW3wk&A^r>icPq`{#In z$gIbL*!#^A4<)*^QKlRfzG&EYG-*>!adBH_gb`ORGjnAghUg!srna zM1BS&r-2<%__IzN8Y6r5J!^ydS-bIlHfvV2_G6SW8|q*;zpLM&{%xumUsY8o6&9bg z_T#g5eo(83#HSy*?)|(pCGnw>*+mZZz72ukrEw);-wDd)f77g&S&?|N@5}&IlHB<6 zMH5xNe9;7w%YU@ULW^IOWR~k@xRra1uM+z6?GY-8;O-oCclXHT34rKF=WlQR#eV&^ z_ugxFe<$*Y=7U7UC=}_dXul!YVf=4XVXCQ;{i@h+=)U*f_x6gkbqgVc@4cTkJ0iIo z6h?o*X!N}Y*=srkT*&q6b#s*dV<7slSG4K363WpUg6;-n4Matk$qV-t-3K|YyOF`o zj}5f7^}EPm$zgh0dMbBEcH`0(fKBG{eb>Ew1spiPD-ykH3L;LewvJrd!4 zK}CH-XEq$xTV*R7LzbjwpN4 z2Q_}H;)U3Eom62e$_+vF2xo>=%$&knRyjddg;nUYlPu)To z$Vxvs)d2le6KvTV}l?F-ANl2?J^OJ?WJX z13e%~H>ertT?TshT_Gy;S4IX#G`W1!F~(Kj7DLFv5)V!;-*h;+s((phf?{Yn6T9d^ znI{+IG%haZQbUa93KS<7267mJ}Xgd$gcDA=OtQDH_&i>tbg8{8-rT6Y#o zpmBOnS&ZPt)CCw%F1T@3T&;o{94)!v7Ii3r>m>x!&3Od@=Jux^V^ocb2)!w&asnh5 z+*$@*TuM}jvE}Ck_3Ft@hF-ln#VmnAp~0Q6Gv}N$HJ{EI+&R6VS>n!i%{k|sQ-VQ- zoO8}O<$O9{YnB^vCk|-toKvI`!JX4Jr<4(T>pU5{^@6(fT<=rA(sB7!MN1VblZ*%< z%!u@SIZ?GSCQ^WOVsug%Q7}%K$!DUN4S_G=QxvBJKAm%B6G{nfq(RiLMA9?s*pyRl zKR1(^!-&QC@=;$a{VKn1U0(?;6Dhdpw3G_Tr#RLl%p$DGh{&2u2&-76bNef!q#mJ- ztcbNWGeR_PjA08J)HrW2P>q=ol>yxNix9Tl+BOZwL<%n?FM3=u!!V44y@DLm*_sBe zHmjtV=KYu zVk^>k5yj=ih2Waq&4T~ytRkFJXzrYig3Imb?H^gN0L*P4SyWl)wT{qkTz>UHhQ8Jm ztpWtFVha*S@4ZCi|^wbS&s`6!dDyeg9bvnAGd#oAI