From c832f6de73a9d2affd6e750c5d35786dab5a2caf Mon Sep 17 00:00:00 2001 From: linning Date: Tue, 27 Jun 2023 03:28:40 +0800 Subject: [PATCH 1/4] Set up domain test infra Signed-off-by: linning --- Cargo.lock | 403 ++++++- Cargo.toml | 2 + domains/client/domain-executor/Cargo.toml | 2 +- domains/service/src/lib.rs | 2 +- domains/test/primitives/Cargo.toml | 28 + domains/test/primitives/src/lib.rs | 30 + domains/test/runtime/evm/Cargo.toml | 129 +++ domains/test/runtime/evm/build.rs | 10 + domains/test/runtime/evm/src/lib.rs | 1060 +++++++++++++++++++ domains/test/runtime/evm/src/precompiles.rs | 66 ++ domains/test/service/Cargo.toml | 70 ++ domains/test/service/src/chain_spec.rs | 115 ++ domains/test/service/src/domain.rs | 444 ++++++++ domains/test/service/src/keyring.rs | 45 + domains/test/service/src/lib.rs | 248 +++++ test/subspace-test-client/Cargo.toml | 3 +- test/subspace-test-client/src/chain_spec.rs | 10 +- 17 files changed, 2624 insertions(+), 43 deletions(-) create mode 100644 domains/test/primitives/Cargo.toml create mode 100644 domains/test/primitives/src/lib.rs create mode 100644 domains/test/runtime/evm/Cargo.toml create mode 100644 domains/test/runtime/evm/build.rs create mode 100644 domains/test/runtime/evm/src/lib.rs create mode 100644 domains/test/runtime/evm/src/precompiles.rs create mode 100644 domains/test/service/Cargo.toml create mode 100644 domains/test/service/src/chain_spec.rs create mode 100644 domains/test/service/src/domain.rs create mode 100644 domains/test/service/src/keyring.rs create mode 100644 domains/test/service/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 801f8eb34d..0686206c88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2165,6 +2165,7 @@ dependencies = [ "domain-client-executor-gossip", "domain-client-message-relayer", "domain-runtime-primitives", + "evm-domain-test-runtime", "futures", "futures-timer", "num-traits", @@ -2267,7 +2268,7 @@ dependencies = [ "fc-rpc", "fc-rpc-core", "fc-storage", - "fp-rpc", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "futures", "jsonrpsee", "pallet-transaction-payment-rpc", @@ -2383,6 +2384,79 @@ dependencies = [ "tracing", ] +[[package]] +name = "domain-test-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "sp-api", + "sp-domains", + "sp-messenger", + "subspace-runtime-primitives", +] + +[[package]] +name = "domain-test-service" +version = "0.1.0" +dependencies = [ + "async-trait", + "domain-client-consensus-relay-chain", + "domain-client-executor", + "domain-eth-service", + "domain-runtime-primitives", + "domain-service", + "domain-test-primitives", + "evm-domain-test-runtime", + "fp-account 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "futures", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc", + "rand 0.8.5", + "sc-client-api", + "sc-consensus", + "sc-consensus-slots", + "sc-executor", + "sc-network", + "sc-network-sync", + "sc-rpc", + "sc-service", + "sc-tracing", + "sc-transaction-pool", + "sc-utils", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-block-builder", + "sp-blockchain", + "sp-core", + "sp-domains", + "sp-inherents", + "sp-keyring", + "sp-messenger", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-timestamp", + "sp-transaction-pool", + "subspace-networking", + "subspace-proof-of-space", + "subspace-runtime-primitives", + "subspace-service", + "subspace-test-client", + "subspace-test-runtime", + "subspace-test-service", + "substrate-frame-rpc-system", + "substrate-test-client", + "tokio", + "tracing", +] + [[package]] name = "downcast" version = "0.11.0" @@ -2698,10 +2772,61 @@ version = "0.1.0" dependencies = [ "domain-pallet-executive", "domain-runtime-primitives", - "fp-account", - "fp-evm", - "fp-rpc", - "fp-self-contained", + "fp-account 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-self-contained 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "frame-benchmarking", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "hex-literal", + "log", + "pallet-balances", + "pallet-base-fee 1.0.0 (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-ethereum 4.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-evm 6.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-evm-chain-id 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-evm-precompile-modexp 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-evm-precompile-sha3fips 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-evm-precompile-simple 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "pallet-messenger", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-transporter", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-core", + "sp-domains", + "sp-inherents", + "sp-io", + "sp-messenger", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "subspace-runtime-primitives", + "substrate-wasm-builder", +] + +[[package]] +name = "evm-domain-test-runtime" +version = "0.1.0" +dependencies = [ + "domain-pallet-executive", + "domain-runtime-primitives", + "domain-test-primitives", + "fp-account 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-self-contained 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "frame-benchmarking", "frame-support", "frame-system", @@ -2710,13 +2835,13 @@ dependencies = [ "hex-literal", "log", "pallet-balances", - "pallet-base-fee", - "pallet-ethereum", - "pallet-evm", - "pallet-evm-chain-id", - "pallet-evm-precompile-modexp", - "pallet-evm-precompile-sha3fips", - "pallet-evm-precompile-simple", + "pallet-base-fee 1.0.0 (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-ethereum 4.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-evm 6.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-evm-chain-id 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-evm-precompile-modexp 2.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-evm-precompile-sha3fips 2.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "pallet-evm-precompile-simple 2.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "pallet-messenger", "pallet-sudo", "pallet-timestamp", @@ -2816,8 +2941,8 @@ version = "2.0.0-dev" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ "async-trait", - "fp-consensus", - "fp-rpc", + "fp-consensus 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "sc-consensus", "sp-api", "sp-block-builder", @@ -2832,7 +2957,7 @@ version = "2.0.0-dev" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ "async-trait", - "fp-storage", + "fp-storage 2.0.0 (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "log", "parity-db", "parity-scale-codec", @@ -2851,8 +2976,8 @@ source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f dependencies = [ "fc-db", "fc-storage", - "fp-consensus", - "fp-rpc", + "fp-consensus 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "futures", "futures-timer", "log", @@ -2877,17 +3002,17 @@ dependencies = [ "fc-mapping-sync", "fc-rpc-core", "fc-storage", - "fp-ethereum", - "fp-evm", - "fp-rpc", - "fp-storage", + "fp-ethereum 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-storage 2.0.0 (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "futures", "hex", "jsonrpsee", "libsecp256k1", "log", "lru 0.8.1", - "pallet-evm", + "pallet-evm 6.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "parity-scale-codec", "prometheus", "rand 0.8.5", @@ -2934,8 +3059,8 @@ source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f dependencies = [ "ethereum", "ethereum-types", - "fp-rpc", - "fp-storage", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-storage 2.0.0 (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "parity-scale-codec", "sc-client-api", "sp-api", @@ -3097,6 +3222,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "fp-account" +version = "1.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "hex", + "impl-serde", + "libsecp256k1", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "fp-consensus" version = "2.0.0-dev" @@ -3109,6 +3252,18 @@ dependencies = [ "sp-std", ] +[[package]] +name = "fp-consensus" +version = "2.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "ethereum", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "fp-ethereum" version = "1.0.0-dev" @@ -3116,7 +3271,21 @@ source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f dependencies = [ "ethereum", "ethereum-types", - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "frame-support", + "num_enum", + "parity-scale-codec", + "sp-std", +] + +[[package]] +name = "fp-ethereum" +version = "1.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "frame-support", "num_enum", "parity-scale-codec", @@ -3138,6 +3307,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "fp-evm" +version = "3.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "evm", + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "fp-rpc" version = "3.0.0-dev" @@ -3145,7 +3329,24 @@ source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f dependencies = [ "ethereum", "ethereum-types", - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", +] + +[[package]] +name = "fp-rpc" +version = "3.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "parity-scale-codec", "scale-info", "sp-api", @@ -3167,6 +3368,18 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "fp-self-contained" +version = "1.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", +] + [[package]] name = "fp-storage" version = "2.0.0" @@ -3176,6 +3389,15 @@ dependencies = [ "serde", ] +[[package]] +name = "fp-storage" +version = "2.0.0" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "parity-scale-codec", + "serde", +] + [[package]] name = "fragile" version = "2.0.0" @@ -6002,7 +6224,21 @@ name = "pallet-base-fee" version = "1.0.0" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "pallet-base-fee" +version = "1.0.0" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "frame-support", "frame-system", "parity-scale-codec", @@ -6083,14 +6319,37 @@ dependencies = [ "ethereum", "ethereum-types", "evm", - "fp-consensus", - "fp-ethereum", - "fp-evm", - "fp-rpc", - "fp-storage", + "fp-consensus 2.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-ethereum 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-storage 2.0.0 (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "frame-support", "frame-system", - "pallet-evm", + "pallet-evm 6.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-ethereum" +version = "4.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "ethereum", + "ethereum-types", + "evm", + "fp-consensus 2.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-ethereum 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-rpc 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-storage 2.0.0 (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "frame-support", + "frame-system", + "pallet-evm 6.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "parity-scale-codec", "scale-info", "sp-io", @@ -6105,8 +6364,33 @@ source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f dependencies = [ "environmental", "evm", - "fp-account", - "fp-evm", + "fp-account 1.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "hex-literal", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "rlp", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm" +version = "6.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "environmental", + "evm", + "fp-account 1.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "frame-benchmarking", "frame-support", "frame-system", @@ -6134,12 +6418,32 @@ dependencies = [ "scale-info", ] +[[package]] +name = "pallet-evm-chain-id" +version = "1.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "num", +] + +[[package]] +name = "pallet-evm-precompile-modexp" +version = "2.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "num", ] @@ -6148,7 +6452,16 @@ name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "tiny-keccak", +] + +[[package]] +name = "pallet-evm-precompile-sha3fips" +version = "2.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "tiny-keccak", ] @@ -6157,7 +6470,17 @@ name = "pallet-evm-precompile-simple" version = "2.0.0-dev" source = "git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3#74483666645e121c0c5e6616f43fdfd8664ea0d3" dependencies = [ - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", + "ripemd", + "sp-io", +] + +[[package]] +name = "pallet-evm-precompile-simple" +version = "2.0.0-dev" +source = "git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4#c13d670b25b5506c1c5243f352941dc46c82ffe4" +dependencies = [ + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "ripemd", "sp-io", ] @@ -10357,7 +10680,7 @@ dependencies = [ "domain-runtime-primitives", "domain-service", "evm-domain-runtime", - "fp-evm", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=74483666645e121c0c5e6616f43fdfd8664ea0d3)", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -10566,6 +10889,7 @@ version = "0.1.0" name = "subspace-test-client" version = "0.1.0" dependencies = [ + "evm-domain-test-runtime", "futures", "sc-chain-spec", "sc-client-api", @@ -10576,6 +10900,7 @@ dependencies = [ "sp-api", "sp-consensus-subspace", "sp-core", + "sp-domains", "sp-runtime", "subspace-archiving", "subspace-core-primitives", diff --git a/Cargo.toml b/Cargo.toml index a736f0d36b..be484c9189 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ members = [ "domains/primitives/*", "domains/runtime/*", "domains/service", + "domains/test/runtime/*", + "domains/test/service", "test/subspace-test-client", "test/subspace-test-runtime", "test/subspace-test-service", diff --git a/domains/client/domain-executor/Cargo.toml b/domains/client/domain-executor/Cargo.toml index 9889376542..82f041dd3d 100644 --- a/domains/client/domain-executor/Cargo.toml +++ b/domains/client/domain-executor/Cargo.toml @@ -45,7 +45,7 @@ tokio = { version = "1.28.2", features = ["macros"] } [dev-dependencies] domain-client-message-relayer = { version = "0.1.0", path = "../relayer" } # domain-test-primitives = { version = "0.1.0", path = "../../test/primitives" } -# domain-test-service = { version = "0.1.0", path = "../../test/service" } +evm-domain-test-runtime = { version = "0.1.0", path = "../../test/runtime/evm" } num-traits = "0.2.15" pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } pallet-domains = { version = "0.1.0", path = "../../../crates/pallet-domains" } diff --git a/domains/service/src/lib.rs b/domains/service/src/lib.rs index 49775682d3..d613bd4b29 100644 --- a/domains/service/src/lib.rs +++ b/domains/service/src/lib.rs @@ -5,7 +5,7 @@ mod domain_tx_pre_validator; pub mod providers; pub mod rpc; -pub use self::domain::{new_full, DomainParams, FullPool, NewFull}; +pub use self::domain::{new_full, DomainExecutor, DomainParams, FullPool, NewFull}; use futures::channel::oneshot; use futures::{FutureExt, StreamExt}; use sc_client_api::{BlockBackend, BlockchainEvents, HeaderBackend, ProofProvider}; diff --git a/domains/test/primitives/Cargo.toml b/domains/test/primitives/Cargo.toml new file mode 100644 index 0000000000..1c6ed7fc64 --- /dev/null +++ b/domains/test/primitives/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "domain-test-primitives" +version = "0.1.0" +authors = ["Subspace Labs "] +edition = "2021" +license = "GPL-3.0-or-later" +homepage = "https://subspace.network" +repository = "https://github.com/subspace/subspace" +include = [ + "/src", + "/Cargo.toml", +] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false, features = ["derive"]} +sp-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f", default-features = false } +sp-domains = { version = "0.1.0", default-features = false, path = "../../../crates/sp-domains" } +sp-messenger = { version = "0.1.0", default-features = false, path = "../../primitives/messenger" } +subspace-runtime-primitives = { version = "0.1.0", path = "../../../crates/subspace-runtime-primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "sp-api/std", + "sp-domains/std", + "sp-messenger/std", + "subspace-runtime-primitives/std", +] diff --git a/domains/test/primitives/src/lib.rs b/domains/test/primitives/src/lib.rs new file mode 100644 index 0000000000..3b4a20ce68 --- /dev/null +++ b/domains/test/primitives/src/lib.rs @@ -0,0 +1,30 @@ +#![cfg_attr(not(feature = "std"), no_std)] +//! Test primitive crates that expose necessary extensions that are used in tests. + +use codec::{Decode, Encode}; +use sp_domains::DomainId; +use sp_messenger::messages::ChannelId; +use subspace_runtime_primitives::Moment; + +sp_api::decl_runtime_apis! { + /// Api that returns the timestamp + pub trait TimestampApi { + /// Api to construct inherent timestamp extrinsic from given time + fn timestamp() -> Moment; + } +} + +sp_api::decl_runtime_apis! { + /// Api for querying onchain state in the test + pub trait OnchainStateApi + where + AccountId: Encode + Decode, + Balance: Encode + Decode + { + /// Api to get the free balance of the given account + fn free_balance(account_id: AccountId) -> Balance; + + /// Returns the last open channel for a given domain. + fn get_open_channel_for_domain(dst_domain_id: DomainId) -> Option; + } +} diff --git a/domains/test/runtime/evm/Cargo.toml b/domains/test/runtime/evm/Cargo.toml new file mode 100644 index 0000000000..6d9577dc15 --- /dev/null +++ b/domains/test/runtime/evm/Cargo.toml @@ -0,0 +1,129 @@ +[package] +name = "evm-domain-test-runtime" +version = "0.1.0" +authors = ["Vedhavyas Singareddi, Liu-Cheng Xu "] +license = "Apache-2.0" +homepage = "https://subspace.network" +repository = "https://github.com/subspace/subspace/" +edition = "2021" +description = "Subspace EVM domain runtime" +include = [ + "/src", + "/build.rs", + "/Cargo.toml", +] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.1", default-features = false, features = ["derive"] } +domain-pallet-executive = { version = "0.1.0", path = "../../../pallets/executive", default-features = false } +domain-test-primitives = { version = "0.1.0", path = "../../primitives", default-features = false } +domain-runtime-primitives = { version = "0.1.0", path = "../../../primitives/runtime", default-features = false } +fp-account = { version = "1.0.0-dev", default-features = false, features = ["serde"], git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +fp-evm = { version = "3.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +fp-rpc = { version = "3.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +fp-self-contained = { version = "1.0.0-dev", default-features = false, features = ["serde"], git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +hex-literal = { version = '0.4.0', optional = true } +log = { version = "0.4.19", default-features = false } +pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-base-fee = { version = "1.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-ethereum = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-evm = { version = "6.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-evm-chain-id = { version = "1.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-evm-precompile-modexp = { version = "2.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-evm-precompile-sha3fips = { version = "2.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-evm-precompile-simple = { version = "2.0.0-dev", default-features = false, git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +pallet-messenger = { version = "0.1.0", path = "../../../pallets/messenger", default-features = false } +pallet-sudo = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-timestamp = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-transaction-payment-rpc-runtime-api = { default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-transporter = { version = "0.1.0", path = "../../../pallets/transporter", default-features = false } +scale-info = { version = "2.7.0", default-features = false, features = ["derive"] } +sp-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-block-builder = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-domains = { version = "0.1.0", path = "../../../../crates/sp-domains", default-features = false } +sp-inherents = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-io = { version = "23.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-messenger = { version = "0.1.0", default-features = false, path = "../../../primitives/messenger" } +sp-offchain = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-session = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-std = { version = "8.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-transaction-pool = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-version = { version = "22.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +subspace-runtime-primitives = { version = "0.1.0", path = "../../../../crates/subspace-runtime-primitives", default-features = false } + +[build-dependencies] +substrate-wasm-builder = { version = "5.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f", optional = true } + +[features] +default = [ + "std", +] +std = [ + "codec/std", + "domain-pallet-executive/std", + "domain-runtime-primitives/std", + "domain-test-primitives/std", + "fp-account/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-support/std", + "frame-system/std", + "frame-system-rpc-runtime-api/std", + "log/std", + "pallet-balances/std", + "pallet-base-fee/std", + "pallet-ethereum/std", + "pallet-evm/std", + "pallet-evm-chain-id/std", + "pallet-evm-precompile-modexp/std", + "pallet-evm-precompile-sha3fips/std", + "pallet-evm-precompile-simple/std", + "pallet-messenger/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-transporter/std", + "scale-info/std", + "sp-api/std", + "sp-block-builder/std", + "sp-core/std", + "sp-domains/std", + "sp-session/std", + "sp-inherents/std", + "sp-io/std", + "sp-messenger/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "subspace-runtime-primitives/std", + "substrate-wasm-builder", +] +# Internal implementation detail, enabled during building of wasm blob. +wasm-builder = [] +runtime-benchmarks = [ + 'hex-literal', + "sp-runtime/runtime-benchmarks", + "frame-benchmarking", + "frame-system-benchmarking", + "frame-system-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", +] diff --git a/domains/test/runtime/evm/build.rs b/domains/test/runtime/evm/build.rs new file mode 100644 index 0000000000..8f021e8381 --- /dev/null +++ b/domains/test/runtime/evm/build.rs @@ -0,0 +1,10 @@ +fn main() { + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } +} diff --git a/domains/test/runtime/evm/src/lib.rs b/domains/test/runtime/evm/src/lib.rs new file mode 100644 index 0000000000..fe9c0141ae --- /dev/null +++ b/domains/test/runtime/evm/src/lib.rs @@ -0,0 +1,1060 @@ +#![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"] + +mod precompiles; + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use codec::{Decode, Encode}; +pub use domain_runtime_primitives::opaque::Header; +pub use domain_runtime_primitives::{opaque, Balance, BlockNumber, Hash, Index}; +use domain_runtime_primitives::{MultiAccountId, TryConvertBack, SLOT_DURATION}; +use fp_account::EthereumSignature; +use fp_self_contained::CheckedSignature; +use frame_support::dispatch::DispatchClass; +use frame_support::traits::{ConstU16, ConstU32, ConstU64, Everything, FindAuthor}; +use frame_support::weights::constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, ParityDbWeight, WEIGHT_REF_TIME_PER_MILLIS, + WEIGHT_REF_TIME_PER_SECOND, +}; +use frame_support::weights::{ConstantMultiplier, IdentityFee, Weight}; +use frame_support::{construct_runtime, parameter_types}; +use frame_system::limits::{BlockLength, BlockWeights}; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction, TransactionStatus}; +use pallet_evm::{ + Account as EVMAccount, EnsureAddressNever, EnsureAddressRoot, FeeCalculator, + IdentityAddressMapping, Runner, +}; +use pallet_transporter::EndpointHandler; +use sp_api::impl_runtime_apis; +use sp_core::crypto::KeyTypeId; +use sp_core::{Get, OpaqueMetadata, H160, H256, U256}; +use sp_domains::DomainId; +use sp_messenger::endpoint::{Endpoint, EndpointHandler as EndpointHandlerT, EndpointId}; +use sp_messenger::messages::{ + ChannelId, CrossDomainMessage, ExtractedStateRootsFromProof, MessageId, + RelayerMessagesWithStorageKey, +}; +use sp_runtime::traits::{ + BlakeTwo256, Block as BlockT, Checkable, Convert, DispatchInfoOf, Dispatchable, + IdentifyAccount, IdentityLookup, PostDispatchInfoOf, UniqueSaturatedInto, Verify, +}; +use sp_runtime::transaction_validity::{ + TransactionSource, TransactionValidity, TransactionValidityError, +}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, ApplyExtrinsicResult, ConsensusEngineId, +}; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; +use sp_std::marker::PhantomData; +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; +use subspace_runtime_primitives::{Moment, SHANNON, SSC}; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = EthereumSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// The address format for describing accounts. +pub type Address = AccountId; + +/// 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; + +/// Precompiles we use for EVM +pub type Precompiles = crate::precompiles::Precompiles; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckMortality, + 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 modules. +pub type Executive = domain_pallet_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + Runtime, +>; + +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, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(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, + } + } +} + +impl_opaque_keys! { + pub struct SessionKeys { + /// Primarily used for adding the executor authority key into the keystore in the dev mode. + pub executor: sp_domains::ExecutorKey, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("subspace-evm-domain"), + impl_name: create_runtime_str!("subspace-evm-domain"), + authoring_version: 0, + spec_version: 0, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 0, + state_version: 0, +}; + +/// The existential deposit. Same with the one on primary chain. +pub const EXISTENTIAL_DEPOSIT: Balance = 500 * SHANNON; + +/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is +/// used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); + +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by +/// `Operational` extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// We allow for 2000ms of compute with a 6 second average block time. +pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 2000; +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS, + u64::MAX, +); +pub const MAXIMUM_BLOCK_LENGTH: u32 = 5 * 1024 * 1024; + +/// 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(), + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + pub const BlockHashCount: BlockNumber = 2400; + + // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. + // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the + // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize + // the lazy contract deletion. + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); +} + +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 Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = Header; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// Runtime version. + type Version = Version; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The weight of database operations that the runtime can invoke. + type DbWeight = ParityDbWeight; + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + type SS58Prefix = ConstU16<2254>; + /// The action to take on a Runtime Upgrade + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = Moment; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + /// 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 WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type MaxHolds = (); +} + +parameter_types! { + pub const TransactionByteFee: Balance = 1; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = OperationalFeeMultiplier; +} + +impl domain_pallet_executive::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = pallet_sudo::weights::SubstrateWeight; +} + +parameter_types! { + pub const StateRootsBound: u32 = 50; + pub const RelayConfirmationDepth: BlockNumber = 1; +} + +parameter_types! { + pub const MaximumRelayers: u32 = 100; + pub const RelayerDeposit: Balance = 100 * SSC; + // TODO: Proper value + pub const CoreDomainId: DomainId = DomainId::new(3u32); +} + +impl pallet_messenger::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SelfDomainId = CoreDomainId; + + fn get_endpoint_response_handler( + endpoint: &Endpoint, + ) -> Option>> { + if endpoint == &Endpoint::Id(TransporterEndpointId::get()) { + Some(Box::new(EndpointHandler(PhantomData::))) + } else { + None + } + } + + type Currency = Balances; + type MaximumRelayers = MaximumRelayers; + type RelayerDeposit = RelayerDeposit; + type DomainInfo = (); + type ConfirmationDepth = RelayConfirmationDepth; + type WeightInfo = pallet_messenger::weights::SubstrateWeight; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +parameter_types! { + pub const TransporterEndpointId: EndpointId = 1; +} + +pub struct AccountId20Converter; + +impl Convert for AccountId20Converter { + fn convert(account_id: AccountId) -> MultiAccountId { + MultiAccountId::AccountId20(account_id.into()) + } +} + +impl TryConvertBack for AccountId20Converter { + fn try_convert_back(multi_account_id: MultiAccountId) -> Option { + match multi_account_id { + MultiAccountId::AccountId20(acc) => Some(AccountId::from(acc)), + _ => None, + } + } +} + +impl pallet_transporter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SelfDomainId = CoreDomainId; + type SelfEndpointId = TransporterEndpointId; + type Currency = Balances; + type Sender = Messenger; + type AccountIdConverter = AccountId20Converter; + type WeightInfo = pallet_transporter::weights::SubstrateWeight; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +pub struct FindAuthorTruncated; + +impl FindAuthor for FindAuthorTruncated { + fn find_author<'a, I>(_digests: I) -> Option + where + I: 'a + IntoIterator, + { + // TODO: returns the executor reward address once we start collecting them + None + } +} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 500ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_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.saturating_div(GAS_PER_SECOND); + +parameter_types! { + /// EVM gas limit + pub BlockGasLimit: U256 = U256::from( + NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS + ); + pub PrecompilesValue: Precompiles = Precompiles::default(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = BaseFee; + 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 PrecompilesType = Precompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EVMChainId; + type BlockGasLimit = BlockGasLimit; + type Runner = pallet_evm::runner::stack::Runner; + type OnChargeTransaction = (); + type OnCreate = (); + type FindAuthor = FindAuthorTruncated; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +parameter_types! { + pub const PostOnlyBlockHash: PostLogContent = PostLogContent::OnlyBlockHash; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostOnlyBlockHash; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub BoundDivision: U256 = U256::from(1024); +} + +parameter_types! { + pub DefaultBaseFeePerGas: U256 = U256::from(1_000_000_000); + // mark it to 5% increments on beyond target weight. + pub DefaultElasticity: Permill = Permill::from_parts(50_000); +} + +pub struct BaseFeeThreshold; + +impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold { + fn lower() -> Permill { + Permill::zero() + } + fn ideal() -> Permill { + Permill::from_parts(500_000) + } + fn upper() -> Permill { + Permill::from_parts(1_000_000) + } +} + +impl pallet_base_fee::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Threshold = BaseFeeThreshold; + type DefaultBaseFeePerGas = DefaultBaseFeePerGas; + type DefaultElasticity = DefaultElasticity; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +// +// NOTE: Currently domain runtime does not naturally support the pallets with inherent extrinsics. +construct_runtime!( + pub struct Runtime where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + // System support stuff. + System: frame_system = 0, + Timestamp: pallet_timestamp = 1, + ExecutivePallet: domain_pallet_executive = 2, + + // monetary stuff + Balances: pallet_balances = 20, + TransactionPayment: pallet_transaction_payment = 21, + + // messenger stuff + // Note: Indexes should match the indexes of the System domain runtime + Messenger: pallet_messenger = 60, + Transporter: pallet_transporter = 61, + + // evm stuff + Ethereum: pallet_ethereum = 80, + EVM: pallet_evm = 81, + EVMChainId: pallet_evm_chain_id = 82, + BaseFee: pallet_base_fee = 83, + + // Sudo account + Sudo: pallet_sudo = 100, + } +); + +#[derive(Clone, Default)] +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") + } +} + +fn extract_xdm_proof_state_roots( + encoded_ext: Vec, +) -> Option> { + if let Ok(ext) = UncheckedExtrinsic::decode(&mut encoded_ext.as_slice()) { + match &ext.0.function { + RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg }) => { + msg.extract_state_roots_from_proof::() + } + RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => { + msg.extract_state_roots_from_proof::() + } + _ => None, + } + } else { + None + } +} + +// TODO: this is inconsistent with other domains. +// Ref https://github.com/subspace/subspace/pull/1434#discussion_r1186633233 +pub fn extract_signers( + extrinsics: Vec, + lookup: &Lookup, +) -> Vec<(Option, UncheckedExtrinsic)> +where + Lookup: sp_runtime::traits::Lookup, +{ + let mut signer_extrinsics = sp_std::vec![]; + for extrinsic in extrinsics { + if let Ok(checked) = extrinsic.clone().check(lookup) { + let maybe_signer = match checked.signed { + CheckedSignature::SelfContained(account_id) => Some(account_id.encode()), + CheckedSignature::Signed(account_id, _) => Some(account_id.encode()), + CheckedSignature::Unsigned => None, + }; + + signer_extrinsics.push((maybe_signer, extrinsic)) + } + } + + signer_extrinsics +} + +impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + 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() -> sp_std::vec::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_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + 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 domain_runtime_primitives::DomainCoreApi for Runtime { + fn extract_signer( + extrinsics: Vec<::Extrinsic>, + ) -> Vec<(Option, ::Extrinsic)> { + let lookup = frame_system::ChainContext::::default(); + extract_signers(extrinsics, &lookup) + } + + fn intermediate_roots() -> Vec<[u8; 32]> { + ExecutivePallet::intermediate_roots() + } + + fn initialize_block_with_post_state_root(header: &::Header) -> Vec { + Executive::initialize_block(header); + Executive::storage_root() + } + + fn apply_extrinsic_with_post_state_root(extrinsic: ::Extrinsic) -> Vec { + let _ = Executive::apply_extrinsic(extrinsic); + Executive::storage_root() + } + + fn construct_set_code_extrinsic(code: Vec) -> Vec { + use codec::Encode; + // Use `set_code_without_checks` instead of `set_code` in the test environment. + let set_code_call = frame_system::Call::set_code_without_checks { code }; + UncheckedExtrinsic::new_unsigned( + domain_pallet_executive::Call::sudo_unchecked_weight_unsigned { + call: Box::new(set_code_call.into()), + weight: Weight::from_parts(0, 0), + }.into() + ).encode() + } + + fn check_transaction_validity( + _uxt: ::Extrinsic, + _block_hash: ::Hash, + ) -> Result<(), domain_runtime_primitives::CheckTxValidityError> { + unimplemented!("TODO: check transaction fee to core-evm") + } + + fn storage_keys_for_verifying_transaction_validity( + who: opaque::AccountId, + ) -> Result>, domain_runtime_primitives::VerifyTxValidityError> { + let sender = AccountId::decode(&mut who.as_slice()) + .map_err(|_| domain_runtime_primitives::VerifyTxValidityError::FailedToDecodeAccountId)?; + Ok(sp_std::vec![ + frame_system::Account::::hashed_key_for(sender), + pallet_transaction_payment::NextFeeMultiplier::::hashed_key().to_vec(), + ]) + } + } + + impl domain_runtime_primitives::InherentExtrinsicApi for Runtime { + fn construct_inherent_timestamp_extrinsic(moment: Moment) -> Option<::Extrinsic> { + Some( + UncheckedExtrinsic::new_unsigned( + pallet_timestamp::Call::set{ now: moment }.into() + ) + ) + } + } + + impl sp_messenger::MessengerApi for Runtime { + fn extract_xdm_proof_state_roots( + extrinsic: Vec, + ) -> Option::Hash, ::Hash>> { + extract_xdm_proof_state_roots(extrinsic) + } + + fn confirmation_depth() -> BlockNumber { + RelayConfirmationDepth::get() + } + } + + impl sp_messenger::RelayerApi for Runtime { + fn domain_id() -> DomainId { + CoreDomainId::get() + } + + fn relay_confirmation_depth() -> BlockNumber { + RelayConfirmationDepth::get() + } + + fn domain_best_number(_domain_id: DomainId) -> Option { + None + } + + fn domain_state_root(_domain_id: DomainId, _number: BlockNumber, _hash: Hash) -> Option{ + None + } + + fn relayer_assigned_messages(relayer_id: AccountId) -> RelayerMessagesWithStorageKey { + Messenger::relayer_assigned_messages(relayer_id) + } + + fn outbox_message_unsigned(msg: CrossDomainMessage::Hash, ::Hash>) -> Option<::Extrinsic> { + Messenger::outbox_message_unsigned(msg) + } + + fn inbox_response_message_unsigned(msg: CrossDomainMessage::Hash, ::Hash>) -> Option<::Extrinsic> { + Messenger::inbox_response_message_unsigned(msg) + } + + fn should_relay_outbox_message(dst_domain_id: DomainId, msg_id: MessageId) -> bool { + Messenger::should_relay_outbox_message(dst_domain_id, msg_id) + } + + fn should_relay_inbox_message_response(dst_domain_id: DomainId, msg_id: MessageId) -> bool { + Messenger::should_relay_inbox_message_response(dst_domain_id, msg_id) + } + } + + 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; + let evm_config = config.as_ref().unwrap_or(::config()); + ::Runner::call( + from, + to, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + evm_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 evm_config = config.as_ref().unwrap_or(::config()); + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + evm_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 { + Some(pallet_base_fee::Elasticity::::get()) + } + + fn gas_limit_multiplier_support() {} + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList, list_benchmark}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + + let mut list = Vec::::new(); + + list_benchmark!(list, extra, frame_system, SystemBench::); + + let storage_info = AllPalletsWithSystem::storage_info(); + + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey, add_benchmark}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // RuntimeEvent Count + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + add_benchmark!(params, batches, frame_system, SystemBench::); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + + impl domain_test_primitives::TimestampApi for Runtime { + fn timestamp() -> Moment { + Timestamp::now() + } + } + + impl domain_test_primitives::OnchainStateApi for Runtime { + fn free_balance(account_id: AccountId) -> Balance { + Balances::free_balance(account_id) + } + + fn get_open_channel_for_domain(dst_domain_id: DomainId) -> Option { + Messenger::get_open_channel_for_domain(dst_domain_id).map(|(c, _)| c) + } + } +} diff --git a/domains/test/runtime/evm/src/precompiles.rs b/domains/test/runtime/evm/src/precompiles.rs new file mode 100644 index 0000000000..a1e11d859f --- /dev/null +++ b/domains/test/runtime/evm/src/precompiles.rs @@ -0,0 +1,66 @@ +use pallet_evm::{ + IsPrecompileResult, Precompile, PrecompileHandle, PrecompileResult, PrecompileSet, +}; +use sp_core::H160; +use sp_std::marker::PhantomData; + +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; + +pub struct Precompiles(PhantomData); + +impl Precompiles +where + R: pallet_evm::Config, +{ + pub fn used_addresses() -> [H160; 7] { + [ + hash(1), + hash(2), + hash(3), + hash(4), + hash(5), + hash(1024), + hash(1025), + ] + } +} + +impl Default for Precompiles { + #[inline] + fn default() -> Self { + Self(PhantomData) + } +} + +impl PrecompileSet for Precompiles +where + R: pallet_evm::Config, +{ + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + match handle.code_address() { + // Ethereum precompiles : + a if a == hash(1) => Some(ECRecover::execute(handle)), + a if a == hash(2) => Some(Sha256::execute(handle)), + a if a == hash(3) => Some(Ripemd160::execute(handle)), + a if a == hash(4) => Some(Identity::execute(handle)), + a if a == hash(5) => Some(Modexp::execute(handle)), + // Non-Frontier specific nor Ethereum precompiles : + a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), + a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), + _ => None, + } + } + + fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: Self::used_addresses().contains(&address), + extra_cost: 0, + } + } +} + +fn hash(a: u64) -> H160 { + H160::from_low_u64_be(a) +} diff --git a/domains/test/service/Cargo.toml b/domains/test/service/Cargo.toml new file mode 100644 index 0000000000..91738b9e13 --- /dev/null +++ b/domains/test/service/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "domain-test-service" +version = "0.1.0" +authors = ["Subspace Labs "] +edition = "2021" +license = "GPL-3.0-or-later" +homepage = "https://subspace.network" +repository = "https://github.com/subspace/subspace" +include = [ + "/src", + "/Cargo.toml", +] + +[dependencies] +async-trait = "0.1.68" +domain-client-consensus-relay-chain = { version = "0.1.0", path = "../../client/consensus-relay-chain" } +domain-client-executor = { version = "0.1.0", path = "../../client/domain-executor" } +domain-eth-service = { version = "0.1.0", path = "../../client/eth-service" } +domain-service = { version = "0.1.0", path = "../../service" } +domain-test-primitives = { version = "0.1.0", path = "../primitives" } +domain-runtime-primitives = { version = "0.1.0", path = "../../primitives/runtime", default-features = false } +evm-domain-test-runtime = { version = "0.1.0", path = "../runtime/evm" } +fp-account = { version = "1.0.0-dev", default-features = false, features = ["serde"], git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +fp-evm = { version = "3.0.0-dev", git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } +fp-rpc = { version = "3.0.0-dev", git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4", features = ['default'] } +futures = "0.3.28" +frame-system = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-system-rpc-runtime-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +frame-support = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +rand = "0.8.5" +pallet-transaction-payment = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +pallet-transaction-payment-rpc = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-client-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-consensus = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-consensus-slots = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-executor = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-network = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-network-sync = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-rpc = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f", default-features = false } +sc-tracing = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-transaction-pool = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sc-utils = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +serde = { version = "1.0.159", features = ["derive"] } +sp-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-application-crypto = { version = "23.0.0", default-features = false, git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-arithmetic = { version = "16.0.0", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-blockchain = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-block-builder = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-core = { version = "21.0.0", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-domains = { version = "0.1.0", path = "../../../crates/sp-domains" } +sp-keyring = { version = "24.0.0", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-messenger = { version = "0.1.0", path = "../../../domains/primitives/messenger" } +sp-offchain = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-inherents = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-runtime = { version = "24.0.0", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f", default-features = false } +sp-session = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-timestamp = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-transaction-pool = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +subspace-networking = { path = "../../../crates/subspace-networking" } +subspace-proof-of-space = { path = "../../../crates/subspace-proof-of-space" } +subspace-runtime-primitives = { version = "0.1.0", path = "../../../crates/subspace-runtime-primitives" } +subspace-service = { version = "0.1.0", path = "../../../crates/subspace-service" } +subspace-test-client = { version = "0.1.0", path = "../../../test/subspace-test-client" } +subspace-test-runtime = { version = "0.1.0", path = "../../../test/subspace-test-runtime" } +subspace-test-service = { version = "0.1.0", path = "../../../test/subspace-test-service" } +substrate-frame-rpc-system = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +substrate-test-client = { version = "2.0.0", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +tokio = { version = "1.28.2", features = ["macros"] } +tracing = "0.1.37" diff --git a/domains/test/service/src/chain_spec.rs b/domains/test/service/src/chain_spec.rs new file mode 100644 index 0000000000..13d6408ce9 --- /dev/null +++ b/domains/test/service/src/chain_spec.rs @@ -0,0 +1,115 @@ +//! Chain specification for the domain test runtime. +use crate::EcdsaKeyring::{Alice, Bob, Charlie, Dave, Eve, Ferdie}; +use evm_domain_test_runtime::{AccountId as AccountId20, Precompiles, Signature}; +use sc_service::{ChainSpec, ChainType, GenericChainSpec}; +use sp_core::{ecdsa, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; +use subspace_runtime_primitives::SSC; + +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed. +pub fn get_account_id_from_seed(seed: &str) -> AccountId20 +where + AccountPublic: From<::Public>, +{ + AccountPublic::from( + TPublic::Pair::from_string(&format!("//{seed}"), None) + .expect("static values are valid; qed") + .public(), + ) + .into_account() +} + +/// Get the chain spec for the given domain. +/// +/// Note: for convenience, the returned chain spec give some specific accounts the ability to +/// win the bundle election for a specific domain with (nearly) 100% probability in each slot: +/// [Evm domain => Alice] +pub fn get_chain_spec() -> Box { + macro_rules! chain_spec_from_genesis { + ( $constructor:expr ) => {{ + GenericChainSpec::from_genesis( + "Local Testnet", + "local_testnet", + ChainType::Local, + $constructor, + vec![], + None, + None, + None, + None, + None, + ) + }}; + } + Box::new(chain_spec_from_genesis!(testnet_evm_genesis)) +} + +fn endowed_accounts() -> Vec { + vec![ + Alice.to_account_id(), + Bob.to_account_id(), + Charlie.to_account_id(), + Dave.to_account_id(), + Eve.to_account_id(), + Ferdie.to_account_id(), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ] +} + +fn testnet_evm_genesis() -> evm_domain_test_runtime::GenesisConfig { + // This is the simplest bytecode to revert without returning any data. + // We will pre-deploy it under all of our precompiles to ensure they can be called from + // within contracts. + // (PUSH1 0x00 PUSH1 0x00 REVERT) + let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD]; + + evm_domain_test_runtime::GenesisConfig { + system: evm_domain_test_runtime::SystemConfig { + code: evm_domain_test_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + transaction_payment: Default::default(), + balances: evm_domain_test_runtime::BalancesConfig { + balances: endowed_accounts() + .iter() + .cloned() + .map(|k| (k, 2_000_000 * SSC)) + .collect(), + }, + messenger: evm_domain_test_runtime::MessengerConfig { + relayers: vec![(Alice.to_account_id(), Alice.to_account_id())], + }, + sudo: evm_domain_test_runtime::SudoConfig { + key: Some(Alice.to_account_id()), + }, + evm_chain_id: evm_domain_test_runtime::EVMChainIdConfig { chain_id: 100 }, + evm: evm_domain_test_runtime::EVMConfig { + // We need _some_ code inserted at the precompile address so that + // the evm will actually call the address. + accounts: Precompiles::used_addresses() + .into_iter() + .map(|addr| { + ( + addr, + fp_evm::GenesisAccount { + nonce: Default::default(), + balance: Default::default(), + storage: Default::default(), + code: revert_bytecode.clone(), + }, + ) + }) + .collect(), + }, + ethereum: Default::default(), + base_fee: Default::default(), + } +} diff --git a/domains/test/service/src/domain.rs b/domains/test/service/src/domain.rs new file mode 100644 index 0000000000..462838eecd --- /dev/null +++ b/domains/test/service/src/domain.rs @@ -0,0 +1,444 @@ +//! Utilities used for testing with the domain. +#![warn(missing_docs)] + +use crate::{construct_extrinsic_generic, node_config, EcdsaKeyring, UncheckedExtrinsicFor}; +use domain_client_executor::ExecutorStreams; +use domain_runtime_primitives::opaque::Block; +use domain_runtime_primitives::{Balance, DomainCoreApi, InherentExtrinsicApi}; +use domain_service::providers::DefaultProvider; +use domain_service::FullClient; +use domain_test_primitives::OnchainStateApi; +use evm_domain_test_runtime; +use evm_domain_test_runtime::AccountId as AccountId20; +use fp_rpc::EthereumRuntimeRPCApi; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi; +use sc_client_api::{BlockchainEvents, HeaderBackend, StateBackendFor}; +use sc_executor::NativeExecutionDispatch; +use sc_network::{NetworkService, NetworkStateInfo}; +use sc_network_sync::SyncingService; +use sc_service::config::MultiaddrWithPeerId; +use sc_service::{BasePath, Role, RpcHandlers, TFullBackend, TaskManager}; +use sc_utils::mpsc::TracingUnboundedSender; +use serde::de::DeserializeOwned; +use sp_api::{ApiExt, ConstructRuntimeApi, Metadata, NumberFor, ProvideRuntimeApi}; +use sp_block_builder::BlockBuilder; +use sp_core::{Decode, Encode, H256}; +use sp_domains::DomainId; +use sp_messenger::{MessengerApi, RelayerApi}; +use sp_offchain::OffchainWorkerApi; +use sp_runtime::traits::Dispatchable; +use sp_runtime::OpaqueExtrinsic; +use sp_session::SessionKeys; +use sp_transaction_pool::runtime_api::TaggedTransactionQueue; +use std::fmt::{Debug, Display}; +use std::future::Future; +use std::marker::PhantomData; +use std::str::FromStr; +use std::sync::Arc; +use subspace_runtime_primitives::opaque::Block as PBlock; +use subspace_runtime_primitives::Index as Nonce; +use subspace_test_service::MockPrimaryNode; +use substrate_frame_rpc_system::AccountNonceApi; +use substrate_test_client::{ + BlockchainEventsExt, RpcHandlersExt, RpcTransactionError, RpcTransactionOutput, +}; + +/// Trait for convert keyring to account id +pub trait FromKeyring { + /// Convert keyring to account id + fn from_keyring(key: EcdsaKeyring) -> Self; +} + +impl FromKeyring for AccountId20 { + fn from_keyring(key: EcdsaKeyring) -> Self { + key.to_account_id() + } +} + +/// The backend type used by the test service. +pub type Backend = TFullBackend; + +type Client = FullClient; + +/// Domain executor for the test service. +pub type DomainExecutor = domain_service::DomainExecutor< + Block, + PBlock, + subspace_test_client::Client, + RuntimeApi, + ExecutorDispatch, + Arc>, +>; + +/// A generic domain node instance used for testing. +pub struct DomainNode +where + RuntimeApi: + ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: ApiExt> + + Metadata + + BlockBuilder + + OffchainWorkerApi + + SessionKeys + + DomainCoreApi + + MessengerApi> + + TaggedTransactionQueue + + AccountNonceApi + + TransactionPaymentRuntimeApi + + RelayerApi>, + ExecutorDispatch: NativeExecutionDispatch + Send + Sync + 'static, + AccountId: Encode + Decode + FromKeyring, +{ + /// The domain id + pub domain_id: DomainId, + /// The node's account key + pub key: EcdsaKeyring, + /// TaskManager's instance. + pub task_manager: TaskManager, + /// Client's instance. + pub client: Arc>, + /// Client backend. + pub backend: Arc, + /// Code executor. + pub code_executor: Arc>, + /// Network service. + pub network_service: Arc>, + /// Sync service. + pub sync_service: Arc>, + /// The `MultiaddrWithPeerId` to this node. This is useful if you want to pass it as "boot node" + /// to other nodes. + pub addr: MultiaddrWithPeerId, + /// RPCHandlers to make RPC queries. + pub rpc_handlers: RpcHandlers, + /// Domain executor. + pub executor: DomainExecutor, + /// Sink to the node's tx pool + pub tx_pool_sink: TracingUnboundedSender>, + _phantom_data: PhantomData<(Runtime, AccountId)>, +} + +impl + DomainNode +where + Runtime: frame_system::Config + + pallet_transaction_payment::Config + + Send + + Sync, + Runtime::RuntimeCall: + Dispatchable + Send + Sync, + crate::BalanceOf: Send + Sync + From + sp_runtime::FixedPointOperand, + RuntimeApi: + ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: ApiExt> + + Metadata + + BlockBuilder + + OffchainWorkerApi + + SessionKeys + + DomainCoreApi + + TaggedTransactionQueue + + AccountNonceApi + + TransactionPaymentRuntimeApi + + InherentExtrinsicApi + + MessengerApi> + + RelayerApi> + + OnchainStateApi + + EthereumRuntimeRPCApi, + ExecutorDispatch: NativeExecutionDispatch + Send + Sync + 'static, + AccountId: DeserializeOwned + + Encode + + Decode + + Clone + + Debug + + Display + + FromStr + + Sync + + Send + + FromKeyring + + 'static, +{ + #[allow(clippy::too_many_arguments)] + async fn build( + domain_id: DomainId, + tokio_handle: tokio::runtime::Handle, + key: EcdsaKeyring, + base_path: BasePath, + domain_nodes: Vec, + domain_nodes_exclusive: bool, + run_relayer: bool, + role: Role, + mock_primary_node: &mut MockPrimaryNode, + ) -> Self { + let service_config = node_config( + domain_id, + tokio_handle.clone(), + key, + domain_nodes, + domain_nodes_exclusive, + role.clone(), + BasePath::new(base_path.path().join(format!("domain-{domain_id:?}"))), + ) + .expect("could not generate domain node Configuration"); + + let span = sc_tracing::tracing::info_span!( + sc_tracing::logging::PREFIX_LOG_SPAN, + name = service_config.network.node_name.as_str() + ); + let _enter = span.enter(); + + let multiaddr = service_config.network.listen_addresses[0].clone(); + + let maybe_relayer_id = if run_relayer { + Some(::from_keyring(key)) + } else { + None + }; + let domain_config = domain_service::DomainConfiguration { + service_config, + maybe_relayer_id, + }; + let executor_streams = ExecutorStreams { + // Set `primary_block_import_throttling_buffer_size` to 0 to ensure the primary chain will not be + // ahead of the execution chain by more than one block, thus slot will not be skipped in test. + primary_block_import_throttling_buffer_size: 0, + block_importing_notification_stream: mock_primary_node + .block_importing_notification_stream(), + imported_block_notification_stream: mock_primary_node + .client + .every_import_notification_stream(), + new_slot_notification_stream: mock_primary_node.new_slot_notification_stream(), + _phantom: Default::default(), + }; + + let gossip_msg_sink = mock_primary_node + .xdm_gossip_worker_builder() + .gossip_msg_sink(); + let domain_params = domain_service::DomainParams { + domain_id, + domain_config, + primary_chain_client: mock_primary_node.client.clone(), + primary_network_sync_oracle: mock_primary_node.sync_service.clone(), + select_chain: mock_primary_node.select_chain.clone(), + executor_streams, + gossip_message_sink: gossip_msg_sink, + provider: DefaultProvider, + }; + + let domain_node = domain_service::new_full::< + _, + _, + _, + _, + _, + _, + RuntimeApi, + ExecutorDispatch, + AccountId, + _, + >(domain_params) + .await + .expect("failed to build domain node"); + + let domain_service::NewFull { + task_manager, + client, + backend, + code_executor, + network_service, + sync_service, + network_starter, + rpc_handlers, + executor, + tx_pool_sink, + .. + } = domain_node; + + if role.is_authority() { + mock_primary_node + .xdm_gossip_worker_builder() + .push_domain_tx_pool_sink(domain_id, tx_pool_sink.clone()); + } + + let addr = MultiaddrWithPeerId { + multiaddr, + peer_id: network_service.local_peer_id(), + }; + + network_starter.start_network(); + + DomainNode { + domain_id, + key, + task_manager, + client, + backend, + code_executor, + network_service, + sync_service, + addr, + rpc_handlers, + executor, + tx_pool_sink, + _phantom_data: Default::default(), + } + } + + /// Wait for `count` blocks to be imported in the node and then exit. This function will not + /// return if no blocks are ever created, thus you should restrict the maximum amount of time of + /// the test execution. + pub fn wait_for_blocks(&self, count: usize) -> impl Future { + self.client.wait_for_blocks(count) + } + + /// Get the nonce of the node account + pub fn account_nonce(&self) -> u32 { + self.client + .runtime_api() + .account_nonce( + self.client.info().best_hash, + ::from_keyring(self.key), + ) + .expect("Fail to get account nonce") + } + + /// Construct an extrinsic with the current nonce of the node account and send it to this node. + pub async fn construct_and_send_extrinsic( + &mut self, + function: impl Into<::RuntimeCall>, + ) -> Result { + let extrinsic = construct_extrinsic_generic::( + &self.client, + function, + self.key, + false, + self.account_nonce(), + ); + self.rpc_handlers.send_transaction(extrinsic.into()).await + } + + /// Construct an extrinsic. + pub fn construct_extrinsic( + &mut self, + nonce: u32, + function: impl Into<::RuntimeCall>, + ) -> UncheckedExtrinsicFor { + construct_extrinsic_generic::(&self.client, function, self.key, false, nonce) + } + + /// Send an extrinsic to this node. + pub async fn send_extrinsic( + &self, + extrinsic: impl Into, + ) -> Result { + self.rpc_handlers.send_transaction(extrinsic.into()).await + } + + /// Get the free balance of the given account + pub fn free_balance(&self, account_id: AccountId) -> Balance { + self.client + .runtime_api() + .free_balance(self.client.info().best_hash, account_id) + .expect("Fail to get account free balance") + } +} + +/// A builder to create a [`DomainNode`]. +pub struct DomainNodeBuilder { + tokio_handle: tokio::runtime::Handle, + key: EcdsaKeyring, + domain_nodes: Vec, + domain_nodes_exclusive: bool, + base_path: BasePath, + run_relayer: bool, +} + +impl DomainNodeBuilder { + /// Create a new instance of `Self`. + /// + /// `tokio_handle` - The tokio handler to use. + /// `key` - The key that will be used to generate the name. + /// `base_path` - Where databases will be stored. + pub fn new( + tokio_handle: tokio::runtime::Handle, + key: EcdsaKeyring, + base_path: BasePath, + ) -> Self { + DomainNodeBuilder { + key, + tokio_handle, + domain_nodes: Vec::new(), + domain_nodes_exclusive: false, + base_path, + run_relayer: false, + } + } + + /// Run relayer with the node account id as the relayer id + pub fn run_relayer(mut self) -> Self { + self.run_relayer = true; + self + } + + /// Instruct the node to exclusively connect to registered parachain nodes. + /// + /// Domain nodes can be registered using [`Self::connect_to_domain_node`]. + pub fn exclusively_connect_to_registered_parachain_nodes(mut self) -> Self { + self.domain_nodes_exclusive = true; + self + } + + /// Make the node connect to the given domain node. + /// + /// By default the node will not be connected to any node or will be able to discover any other + /// node. + pub fn connect_to_domain_node(mut self, addr: MultiaddrWithPeerId) -> Self { + self.domain_nodes.push(addr); + self + } + + /// Build a evm domain node + pub async fn build_evm_node( + self, + role: Role, + mock_primary_node: &mut MockPrimaryNode, + ) -> EvmDomainNode { + DomainNode::build( + DomainId::new(3u32), + self.tokio_handle, + self.key, + self.base_path, + self.domain_nodes, + self.domain_nodes_exclusive, + self.run_relayer, + role, + mock_primary_node, + ) + .await + } +} + +/// Evm domain executor instance. +pub struct EVMDomainExecutorDispatch; + +impl NativeExecutionDispatch for EVMDomainExecutorDispatch { + type ExtendHostFunctions = (); + + fn dispatch(method: &str, data: &[u8]) -> Option> { + evm_domain_test_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + evm_domain_test_runtime::native_version() + } +} + +/// The evm domain node +pub type EvmDomainNode = DomainNode< + evm_domain_test_runtime::Runtime, + evm_domain_test_runtime::RuntimeApi, + EVMDomainExecutorDispatch, + AccountId20, +>; + +/// The evm domain client +pub type EvmDomainClient = Client; diff --git a/domains/test/service/src/keyring.rs b/domains/test/service/src/keyring.rs new file mode 100644 index 0000000000..9694c9a607 --- /dev/null +++ b/domains/test/service/src/keyring.rs @@ -0,0 +1,45 @@ +//! Set of test accounts. +use fp_account::AccountId20; +use sp_core::ecdsa::{Pair, Public, Signature}; +use sp_core::{ecdsa, keccak_256, Pair as PairT}; + +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + /// Sign `msg`. + pub fn sign(self, msg: &[u8]) -> Signature { + let msg = keccak_256(msg); + self.pair().sign_prehashed(&msg) + } + + /// Return key pair. + pub fn pair(self) -> Pair { + ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap() + } + + /// Return public key. + pub fn public(self) -> Public { + self.pair().public() + } + + /// Return seed string. + pub fn to_seed(self) -> String { + format!("//{:?}", self) + } + + /// Return account id + pub fn to_account_id(self) -> AccountId20 { + self.public().into() + } +} diff --git a/domains/test/service/src/lib.rs b/domains/test/service/src/lib.rs new file mode 100644 index 0000000000..e0579d838a --- /dev/null +++ b/domains/test/service/src/lib.rs @@ -0,0 +1,248 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Crate used for testing with Domain. + +#![warn(missing_docs)] + +pub mod chain_spec; +pub mod domain; +pub mod keyring; + +pub use keyring::Keyring as EcdsaKeyring; +pub use sp_keyring::Sr25519Keyring; + +use domain_runtime_primitives::opaque::Block; +use evm_domain_test_runtime::{Address, Signature}; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use sc_client_api::execution_extensions::ExecutionStrategies; +use sc_network::config::{NonReservedPeerMode, TransportConfig}; +use sc_network::multiaddr; +use sc_service::config::{ + DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, NetworkConfiguration, + OffchainWorkerConfig, PruningMode, WasmExecutionMethod, WasmtimeInstantiationStrategy, +}; +use sc_service::{ + BasePath, BlocksPruning, Configuration as ServiceConfiguration, Error as ServiceError, Role, +}; +use sp_arithmetic::traits::SaturatedConversion; +use sp_blockchain::HeaderBackend; +use sp_core::{Get, H256}; +use sp_domains::DomainId; +use sp_runtime::codec::Encode; +use sp_runtime::generic; +use sp_runtime::traits::Dispatchable; + +pub use domain::*; +pub use evm_domain_test_runtime; + +/// Create a domain node `Configuration`. +/// +/// By default an in-memory socket will be used, therefore you need to provide nodes if you want the +/// node to be connected to other nodes. If `nodes_exclusive` is `true`, the node will only connect +/// to the given `nodes` and not to any other node. +pub fn node_config( + domain_id: DomainId, + tokio_handle: tokio::runtime::Handle, + key: EcdsaKeyring, + nodes: Vec, + nodes_exclusive: bool, + role: Role, + base_path: BasePath, +) -> Result { + let root = base_path.path().to_path_buf(); + let key_seed = key.to_seed(); + + let domain_name = format!("Domain{domain_id:?}"); + + let mut network_config = NetworkConfiguration::new( + format!("{key_seed} ({domain_name})"), + "network/test/0.1", + Default::default(), + None, + ); + + if nodes_exclusive { + network_config.default_peers_set.reserved_nodes = nodes; + network_config.default_peers_set.non_reserved_mode = NonReservedPeerMode::Deny; + } else { + network_config.boot_nodes = nodes; + } + + network_config.allow_non_globals_in_dht = true; + + network_config + .listen_addresses + .push(multiaddr::Protocol::Memory(rand::random()).into()); + + // NOTE: Block sync is disabled for the domain subnet thus the major sync state may not be accurate, + // which will cause transaction not propagate through network properly, setting the `force_synced` + // flag can workaround this issue. + network_config.force_synced = true; + + network_config.transport = TransportConfig::MemoryOnly; + + Ok(ServiceConfiguration { + impl_name: "domain-test-node".to_string(), + impl_version: "0.1".to_string(), + role, + tokio_handle, + transaction_pool: Default::default(), + network: network_config, + keystore: KeystoreConfig::InMemory, + database: DatabaseSource::ParityDb { + path: root.join("paritydb"), + }, + trie_cache_maximum_size: Some(16 * 1024 * 1024), + state_pruning: Some(PruningMode::ArchiveAll), + blocks_pruning: BlocksPruning::KeepAll, + chain_spec: chain_spec::get_chain_spec(), + wasm_method: WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, + // NOTE: we enforce the use of the native runtime to make the errors more debuggable + execution_strategies: ExecutionStrategies { + syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible, + importing: sc_client_api::ExecutionStrategy::NativeWhenPossible, + block_construction: sc_client_api::ExecutionStrategy::NativeWhenPossible, + offchain_worker: sc_client_api::ExecutionStrategy::NativeWhenPossible, + other: sc_client_api::ExecutionStrategy::NativeWhenPossible, + }, + rpc_addr: None, + rpc_max_request_size: 0, + rpc_max_response_size: 0, + rpc_id_provider: None, + rpc_max_subs_per_conn: 0, + rpc_port: 0, + rpc_max_connections: 0, + rpc_cors: None, + rpc_methods: Default::default(), + prometheus_config: None, + telemetry_endpoints: None, + default_heap_pages: None, + offchain_worker: OffchainWorkerConfig { + enabled: true, + indexing_enabled: false, + }, + force_authoring: false, + disable_grandpa: false, + dev_key_seed: Some(key_seed), + tracing_targets: None, + tracing_receiver: Default::default(), + max_runtime_instances: 8, + announce_block: true, + data_path: base_path.path().into(), + base_path, + informant_output_format: Default::default(), + wasm_runtime_overrides: None, + runtime_cache_size: 2, + }) +} + +type SignedExtraFor = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckMortality, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); + +type UncheckedExtrinsicFor = generic::UncheckedExtrinsic< + Address, + ::RuntimeCall, + Signature, + SignedExtraFor, +>; + +type BalanceOf = <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::Balance; + +/// Construct an extrinsic that can be applied to the test runtime. +pub fn construct_extrinsic_generic( + client: impl AsRef, + function: impl Into<::RuntimeCall>, + caller: EcdsaKeyring, + immortal: bool, + nonce: u32, +) -> UncheckedExtrinsicFor +where + Runtime: frame_system::Config + + pallet_transaction_payment::Config + + Send + + Sync, + Runtime::RuntimeCall: + Dispatchable + Send + Sync, + BalanceOf: Send + Sync + From + sp_runtime::FixedPointOperand, + Client: HeaderBackend, +{ + let function = function.into(); + let current_block_hash = client.as_ref().info().best_hash; + let current_block = client.as_ref().info().best_number.saturated_into(); + let genesis_block = client.as_ref().hash(0).unwrap().unwrap(); + let period = ::BlockHashCount::get() + .checked_next_power_of_two() + .map(|c| c / 2) + .unwrap_or(2) as u64; + let tip = 0; + let extra: SignedExtraFor = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckMortality::::from(if immortal { + generic::Era::Immortal + } else { + generic::Era::mortal(period, current_block) + }), + frame_system::CheckNonce::::from(nonce.into()), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(tip.into()), + ); + let raw_payload = generic::SignedPayload::< + ::RuntimeCall, + SignedExtraFor, + >::from_raw( + function.clone(), + extra.clone(), + ((), 0, 0, genesis_block, current_block_hash, (), (), ()), + ); + let signature = raw_payload.using_encoded(|e| caller.sign(e)); + UncheckedExtrinsicFor::::new_signed( + function, + caller.to_account_id(), + Signature::new(signature), + extra, + ) +} + +/// Construct an unsigned extrinsic that can be applied to the test runtime. +pub fn construct_unsigned_extrinsic( + function: impl Into<::RuntimeCall>, +) -> UncheckedExtrinsicFor +where + Runtime: frame_system::Config + + pallet_transaction_payment::Config + + Send + + Sync, + Runtime::RuntimeCall: + Dispatchable + Send + Sync, + BalanceOf: Send + Sync + From + sp_runtime::FixedPointOperand, +{ + let function = function.into(); + UncheckedExtrinsicFor::::new_unsigned(function) +} diff --git a/test/subspace-test-client/Cargo.toml b/test/subspace-test-client/Cargo.toml index 47cb8802aa..54c59b3f7d 100644 --- a/test/subspace-test-client/Cargo.toml +++ b/test/subspace-test-client/Cargo.toml @@ -15,6 +15,7 @@ include = [ targets = ["x86_64-unknown-linux-gnu"] [dependencies] +evm-domain-test-runtime = { version = "0.1.0", path = "../../domains/test/runtime/evm" } futures = "0.3.28" schnorrkel = "0.9.1" sc-chain-spec = { git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } @@ -25,8 +26,8 @@ sc-service = { git = "https://github.com/subspace/substrate", rev = "28e33f78a3a sp-api = { git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } sp-consensus-subspace = { version = "0.1.0", path = "../../crates/sp-consensus-subspace" } sp-core = { git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } +sp-domains = { version = "0.1.0", path = "../../crates/sp-domains" } sp-runtime = { git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } -# system-domain-test-runtime = { version = "0.1.0", path = "../../domains/test/runtime/system" } subspace-archiving = { path = "../../crates/subspace-archiving" } subspace-core-primitives = { path = "../../crates/subspace-core-primitives" } subspace-erasure-coding = { path = "../../crates/subspace-erasure-coding" } diff --git a/test/subspace-test-client/src/chain_spec.rs b/test/subspace-test-client/src/chain_spec.rs index e97e58b2c8..24d52d7cd6 100644 --- a/test/subspace-test-client/src/chain_spec.rs +++ b/test/subspace-test-client/src/chain_spec.rs @@ -2,6 +2,7 @@ use sc_chain_spec::ChainType; use sp_core::{sr25519, Pair, Public}; +use sp_domains::{GenesisDomainRuntime, RuntimeType}; use sp_runtime::traits::{IdentifyAccount, Verify}; use subspace_runtime_primitives::{AccountId, Balance, BlockNumber, Signature}; use subspace_test_runtime::{ @@ -91,7 +92,14 @@ fn create_genesis_config( }, vesting: VestingConfig { vesting }, domains: DomainsConfig { - genesis_domain_runtime: None, + genesis_domain_runtime: Some(GenesisDomainRuntime { + name: b"evm".to_vec(), + runtime_type: RuntimeType::Evm, + runtime_version: evm_domain_test_runtime::VERSION, + code: evm_domain_test_runtime::WASM_BINARY + .unwrap_or_else(|| panic!("EVM domain runtime not available")) + .to_owned(), + }), }, } } From 568a141398d3e52a828a769afdf4ac91a553a1ce Mon Sep 17 00:00:00 2001 From: linning Date: Tue, 27 Jun 2023 03:30:43 +0800 Subject: [PATCH 2/4] Enable domain tests Signed-off-by: linning --- Cargo.lock | 3 + crates/subspace-fraud-proof/Cargo.toml | 2 +- crates/subspace-fraud-proof/src/lib.rs | 5 +- crates/subspace-fraud-proof/src/tests.rs | 307 +++++++++--------- domains/client/domain-executor/Cargo.toml | 3 +- .../client/domain-executor/src/aux_schema.rs | 4 +- domains/client/domain-executor/src/lib.rs | 5 +- domains/client/domain-executor/src/tests.rs | 235 ++++++-------- 8 files changed, 268 insertions(+), 296 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0686206c88..d5e1356851 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2165,6 +2165,8 @@ dependencies = [ "domain-client-executor-gossip", "domain-client-message-relayer", "domain-runtime-primitives", + "domain-test-primitives", + "domain-test-service", "evm-domain-test-runtime", "futures", "futures-timer", @@ -10599,6 +10601,7 @@ dependencies = [ "domain-block-builder", "domain-block-preprocessor", "domain-runtime-primitives", + "domain-test-service", "frame-support", "futures", "hash-db 0.16.0", diff --git a/crates/subspace-fraud-proof/Cargo.toml b/crates/subspace-fraud-proof/Cargo.toml index e1d1d3ffb4..9f03981ea8 100644 --- a/crates/subspace-fraud-proof/Cargo.toml +++ b/crates/subspace-fraud-proof/Cargo.toml @@ -33,7 +33,7 @@ tracing = "0.1.37" [dev-dependencies] domain-block-builder = { version = "0.1.0", path = "../../domains/client/block-builder" } -# domain-test-service = { version = "0.1.0", path = "../../domains/test/service" } +domain-test-service = { version = "0.1.0", path = "../../domains/test/service" } pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } pallet-domains = { version = "0.1.0", path = "../../crates/pallet-domains" } sc-cli = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f", default-features = false } diff --git a/crates/subspace-fraud-proof/src/lib.rs b/crates/subspace-fraud-proof/src/lib.rs index 4728996c9e..740355effe 100644 --- a/crates/subspace-fraud-proof/src/lib.rs +++ b/crates/subspace-fraud-proof/src/lib.rs @@ -6,9 +6,8 @@ pub mod domain_extrinsics_builder; mod domain_runtime_code; pub mod invalid_state_transition_proof; pub mod invalid_transaction_proof; -// TODO: Unlock once domain test infra is workable again. -// #[cfg(test)] -// mod tests; +#[cfg(test)] +mod tests; pub mod verifier_api; use futures::channel::oneshot; diff --git a/crates/subspace-fraud-proof/src/tests.rs b/crates/subspace-fraud-proof/src/tests.rs index ca94d749be..8caa0f6199 100644 --- a/crates/subspace-fraud-proof/src/tests.rs +++ b/crates/subspace-fraud-proof/src/tests.rs @@ -3,16 +3,17 @@ use crate::invalid_state_transition_proof::{ExecutionProver, InvalidStateTransit use crate::invalid_transaction_proof::InvalidTransactionProofVerifier; use crate::verifier_api::VerifierApi; use crate::ProofVerifier; -use codec::{Decode, Encode}; +use codec::Encode; use domain_block_builder::{BlockBuilder, RecordProof}; use domain_runtime_primitives::{DomainCoreApi, Hash}; -use domain_test_service::system_domain::SClient as DomainClient; -use domain_test_service::system_domain_test_runtime::{Address, Header}; -use domain_test_service::Keyring::{Alice, Bob, Charlie, Dave, Ferdie, One}; +use domain_test_service::domain::EvmDomainClient as DomainClient; +use domain_test_service::evm_domain_test_runtime::Header; +use domain_test_service::EcdsaKeyring::{Alice, Bob, Charlie, Dave}; +use domain_test_service::Sr25519Keyring::Ferdie; use sc_client_api::{HeaderBackend, StorageProof}; use sc_service::{BasePath, Role}; use sp_api::ProvideRuntimeApi; -use sp_core::{Pair, H256}; +use sp_core::H256; use sp_domain_digests::AsPredigest; use sp_domains::fraud_proof::{ ExecutionPhase, FraudProof, InvalidStateTransitionProof, VerificationError, @@ -20,7 +21,6 @@ use sp_domains::fraud_proof::{ use sp_domains::DomainId; use sp_runtime::generic::{Digest, DigestItem}; use sp_runtime::traits::{BlakeTwo256, Header as HeaderT}; -use sp_runtime::OpaqueExtrinsic; use std::sync::Arc; use subspace_runtime_primitives::opaque::Block; use subspace_test_client::Client; @@ -89,9 +89,10 @@ impl VerifierApi for TestVerifierClient { } // Use the system domain id for testing -const TEST_DOMAIN_ID: DomainId = DomainId::SYSTEM; +const TEST_DOMAIN_ID: DomainId = DomainId::new(3u32); #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn execution_proof_creation_and_verification_should_work() { let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -108,22 +109,22 @@ async fn execution_proof_creation_and_verification_should_work() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let mut alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let mut alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; - // Run Bob (a system domain full node) - let bob = domain_test_service::SystemDomainNodeBuilder::new( + // Run Bob (a evm domain full node) + let bob = domain_test_service::DomainNodeBuilder::new( tokio_handle, Bob, BasePath::new(directory.path().join("bob")), ) - .build_with_mock_primary_node(Role::Full, &mut ferdie) + .build_evm_node(Role::Full, &mut ferdie) .await; // Bob is able to sync blocks. @@ -133,21 +134,21 @@ async fn execution_proof_creation_and_verification_should_work() { let transfer_to_charlie = alice.construct_extrinsic( alice_nonce, pallet_balances::Call::transfer { - dest: Address::Id(Charlie.public().into()), + dest: Charlie.to_account_id(), value: 8, }, ); let transfer_to_dave = alice.construct_extrinsic( alice_nonce + 1, pallet_balances::Call::transfer { - dest: Address::Id(Dave.public().into()), + dest: Dave.to_account_id(), value: 8, }, ); let transfer_to_charlie_again = alice.construct_extrinsic( alice_nonce + 2, pallet_balances::Call::transfer { - dest: Address::Id(Charlie.public().into()), + dest: Charlie.to_account_id(), value: 88, }, ); @@ -405,6 +406,7 @@ async fn execution_proof_creation_and_verification_should_work() { } #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn invalid_execution_proof_should_not_work() { let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -421,22 +423,22 @@ async fn invalid_execution_proof_should_not_work() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let mut alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let mut alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; - // Run Bob (a system domain full node) - let bob = domain_test_service::SystemDomainNodeBuilder::new( + // Run Bob (a evm domain full node) + let bob = domain_test_service::DomainNodeBuilder::new( tokio_handle, Bob, BasePath::new(directory.path().join("bob")), ) - .build_with_mock_primary_node(Role::Full, &mut ferdie) + .build_evm_node(Role::Full, &mut ferdie) .await; // Bob is able to sync blocks. @@ -446,14 +448,14 @@ async fn invalid_execution_proof_should_not_work() { let transfer_to_charlie = alice.construct_extrinsic( alice_nonce, pallet_balances::Call::transfer { - dest: Address::Id(Charlie.public().into()), + dest: Charlie.to_account_id(), value: 8, }, ); let transfer_to_charlie_again = alice.construct_extrinsic( alice_nonce + 1, pallet_balances::Call::transfer { - dest: Address::Id(Charlie.public().into()), + dest: Charlie.to_account_id(), value: 8, }, ); @@ -611,131 +613,132 @@ async fn invalid_execution_proof_should_not_work() { assert!(proof_verifier.verify(&fraud_proof).is_ok()); } -#[substrate_test_utils::test(flavor = "multi_thread")] -async fn test_invalid_transaction_proof_creation_and_verification() { - let directory = TempDir::new().expect("Must be able to create temporary directory"); - - let mut builder = sc_cli::LoggerBuilder::new("runtime=debug"); - builder.with_colors(false); - let _ = builder.init(); - - let tokio_handle = tokio::runtime::Handle::current(); - - // Start Ferdie - let mut ferdie = MockPrimaryNode::run_mock_primary_node( - tokio_handle.clone(), - Ferdie, - BasePath::new(directory.path().join("ferdie")), - ); - - // Run Alice (a system domain authority node) - let mut alice = domain_test_service::SystemDomainNodeBuilder::new( - tokio_handle.clone(), - Alice, - BasePath::new(directory.path().join("alice")), - ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) - .await; - - produce_blocks!(ferdie, alice, 3).await.unwrap(); - - alice - .construct_and_send_extrinsic(pallet_balances::Call::transfer { - dest: domain_test_service::system_domain_test_runtime::Address::Id(One.public().into()), - value: 500 + 1, - }) - .await - .expect("Send an extrinsic to transfer some balance from Alice to One"); - - ferdie.produce_slot_and_wait_for_bundle_submission().await; - - produce_blocks!(ferdie, alice, 1).await.unwrap(); - - let (_slot, maybe_bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; - - produce_blocks!(ferdie, alice, 3).await.unwrap(); - - // This is an invalid transaction. - let transfer_from_one_to_bob = alice.construct_extrinsic_with_caller( - One, - pallet_balances::Call::transfer { - dest: domain_test_service::system_domain_test_runtime::Address::Id(Bob.public().into()), - value: 1000, - }, - ); - - let mut bundle_with_bad_extrinsics = maybe_bundle.unwrap(); - bundle_with_bad_extrinsics.extrinsics = - vec![OpaqueExtrinsic::from_bytes(&transfer_from_one_to_bob.encode()).unwrap()]; - bundle_with_bad_extrinsics.sealed_header.signature = alice - .key - .pair() - .sign(bundle_with_bad_extrinsics.sealed_header.pre_hash().as_ref()) - .into(); - - alice - .gossip_message_validator - .validate_gossiped_bundle(&bundle_with_bad_extrinsics) - .expect("Create an invalid transaction proof and submit to tx pool"); - - let extract_fraud_proof_from_tx_pool = || { - let ready_txs = ferdie - .transaction_pool - .pool() - .validated_pool() - .ready() - .collect::>(); - - ready_txs - .into_iter() - .find_map(|ready_tx| { - let uxt = subspace_test_runtime::UncheckedExtrinsic::decode( - &mut ready_tx.data.encode().as_slice(), - ) - .unwrap(); - match uxt.function { - subspace_test_runtime::RuntimeCall::Domains( - pallet_domains::Call::submit_fraud_proof { fraud_proof }, - ) => Some(fraud_proof), - _ => None, - } - }) - .expect("Can not find submit_fraud_proof extrinsic") - }; - - let good_invalid_transaction_proof = extract_fraud_proof_from_tx_pool(); - - let domain_extrinsics_builder = - DomainExtrinsicsBuilder::new(ferdie.client.clone(), Arc::new(ferdie.executor.clone())); - - let invalid_state_transition_proof_verifier = InvalidStateTransitionProofVerifier::new( - ferdie.client.clone(), - ferdie.executor.clone(), - TestVerifierClient::new(ferdie.client.clone(), alice.client.clone()), - domain_extrinsics_builder.clone(), - ); - - let invalid_transaction_proof_verifier = InvalidTransactionProofVerifier::new( - ferdie.client.clone(), - Arc::new(ferdie.executor.clone()), - TestVerifierClient::new(ferdie.client.clone(), alice.client.clone()), - domain_extrinsics_builder, - ); - - let proof_verifier = ProofVerifier::::new( - Arc::new(invalid_transaction_proof_verifier), - Arc::new(invalid_state_transition_proof_verifier), - ); - - assert!( - proof_verifier - .verify(&good_invalid_transaction_proof) - .is_ok(), - "Valid proof must be accepeted" - ); - - ferdie - .produce_blocks(1) - .await - .expect("FraudProof verification in the block import pipeline is fine too"); -} +// TODO: Unlock test when gossip message validator are supported in DecEx v2. +// #[substrate_test_utils::test(flavor = "multi_thread")] +// async fn test_invalid_transaction_proof_creation_and_verification() { +// let directory = TempDir::new().expect("Must be able to create temporary directory"); + +// let mut builder = sc_cli::LoggerBuilder::new("runtime=debug"); +// builder.with_colors(false); +// let _ = builder.init(); + +// let tokio_handle = tokio::runtime::Handle::current(); + +// // Start Ferdie +// let mut ferdie = MockPrimaryNode::run_mock_primary_node( +// tokio_handle.clone(), +// Ferdie, +// BasePath::new(directory.path().join("ferdie")), +// ); + +// // Run Alice (a system domain authority node) +// let mut alice = domain_test_service::DomainNodeBuilder::new( +// tokio_handle.clone(), +// Alice, +// BasePath::new(directory.path().join("alice")), +// ) +// .build_evm_node(Role::Authority, &mut ferdie) +// .await; + +// produce_blocks!(ferdie, alice, 3).await.unwrap(); + +// alice +// .construct_and_send_extrinsic(pallet_balances::Call::transfer { +// dest: domain_test_service::evm_domain_test_runtime::Address::Id(One.public().into()), +// value: 500 + 1, +// }) +// .await +// .expect("Send an extrinsic to transfer some balance from Alice to One"); + +// ferdie.produce_slot_and_wait_for_bundle_submission().await; + +// produce_blocks!(ferdie, alice, 1).await.unwrap(); + +// let (_slot, maybe_bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; + +// produce_blocks!(ferdie, alice, 3).await.unwrap(); + +// // This is an invalid transaction. +// let transfer_from_one_to_bob = alice.construct_extrinsic_with_caller( +// One, +// pallet_balances::Call::transfer { +// dest: domain_test_service::evm_domain_test_runtime::Address::Id(Bob.public().into()), +// value: 1000, +// }, +// ); + +// let mut bundle_with_bad_extrinsics = maybe_bundle.unwrap(); +// bundle_with_bad_extrinsics.extrinsics = +// vec![OpaqueExtrinsic::from_bytes(&transfer_from_one_to_bob.encode()).unwrap()]; +// bundle_with_bad_extrinsics.sealed_header.signature = alice +// .key +// .pair() +// .sign(bundle_with_bad_extrinsics.sealed_header.pre_hash().as_ref()) +// .into(); + +// alice +// .gossip_message_validator +// .validate_gossiped_bundle(&bundle_with_bad_extrinsics) +// .expect("Create an invalid transaction proof and submit to tx pool"); + +// let extract_fraud_proof_from_tx_pool = || { +// let ready_txs = ferdie +// .transaction_pool +// .pool() +// .validated_pool() +// .ready() +// .collect::>(); + +// ready_txs +// .into_iter() +// .find_map(|ready_tx| { +// let uxt = subspace_test_runtime::UncheckedExtrinsic::decode( +// &mut ready_tx.data.encode().as_slice(), +// ) +// .unwrap(); +// match uxt.function { +// subspace_test_runtime::RuntimeCall::Domains( +// pallet_domains::Call::submit_fraud_proof { fraud_proof }, +// ) => Some(fraud_proof), +// _ => None, +// } +// }) +// .expect("Can not find submit_fraud_proof extrinsic") +// }; + +// let good_invalid_transaction_proof = extract_fraud_proof_from_tx_pool(); + +// let domain_extrinsics_builder = +// DomainExtrinsicsBuilder::new(ferdie.client.clone(), Arc::new(ferdie.executor.clone())); + +// let invalid_state_transition_proof_verifier = InvalidStateTransitionProofVerifier::new( +// ferdie.client.clone(), +// ferdie.executor.clone(), +// TestVerifierClient::new(ferdie.client.clone(), alice.client.clone()), +// domain_extrinsics_builder.clone(), +// ); + +// let invalid_transaction_proof_verifier = InvalidTransactionProofVerifier::new( +// ferdie.client.clone(), +// Arc::new(ferdie.executor.clone()), +// TestVerifierClient::new(ferdie.client.clone(), alice.client.clone()), +// domain_extrinsics_builder, +// ); + +// let proof_verifier = ProofVerifier::::new( +// Arc::new(invalid_transaction_proof_verifier), +// Arc::new(invalid_state_transition_proof_verifier), +// ); + +// assert!( +// proof_verifier +// .verify(&good_invalid_transaction_proof) +// .is_ok(), +// "Valid proof must be accepeted" +// ); + +// ferdie +// .produce_blocks(1) +// .await +// .expect("FraudProof verification in the block import pipeline is fine too"); +// } diff --git a/domains/client/domain-executor/Cargo.toml b/domains/client/domain-executor/Cargo.toml index 82f041dd3d..b674cf7f35 100644 --- a/domains/client/domain-executor/Cargo.toml +++ b/domains/client/domain-executor/Cargo.toml @@ -44,7 +44,8 @@ tokio = { version = "1.28.2", features = ["macros"] } [dev-dependencies] domain-client-message-relayer = { version = "0.1.0", path = "../relayer" } -# domain-test-primitives = { version = "0.1.0", path = "../../test/primitives" } +domain-test-service = { version = "0.1.0", path = "../../test/service" } +domain-test-primitives = { version = "0.1.0", path = "../../test/primitives" } evm-domain-test-runtime = { version = "0.1.0", path = "../../test/runtime/evm" } num-traits = "0.2.15" pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "28e33f78a3aa8ac4c6753108bc0471273ff6bf6f" } diff --git a/domains/client/domain-executor/src/aux_schema.rs b/domains/client/domain-executor/src/aux_schema.rs index 0c323988df..dd9c6f3322 100644 --- a/domains/client/domain-executor/src/aux_schema.rs +++ b/domains/client/domain-executor/src/aux_schema.rs @@ -390,11 +390,10 @@ where Ok(None) } -/* TODO: Unlock once domain test infra is workable again. #[cfg(test)] mod tests { use super::*; - use domain_test_service::system_domain_test_runtime::Block; + use domain_test_service::evm_domain_test_runtime::Block; use sc_client_api::backend::NewBlockState; use sc_client_api::{Backend, BlockImportOperation}; use sp_core::hash::H256; @@ -759,4 +758,3 @@ mod tests { assert!(bad_receipts_at(30).is_none()); } } -*/ diff --git a/domains/client/domain-executor/src/lib.rs b/domains/client/domain-executor/src/lib.rs index 495962cd61..a506dcfdb5 100644 --- a/domains/client/domain-executor/src/lib.rs +++ b/domains/client/domain-executor/src/lib.rs @@ -73,9 +73,8 @@ mod executor; mod fraud_proof; mod parent_chain; mod sortition; -// TODO: Unlock once domain test infra is workable again. -// #[cfg(test)] -// mod tests; +#[cfg(test)] +mod tests; mod utils; pub use self::executor::Executor; diff --git a/domains/client/domain-executor/src/tests.rs b/domains/client/domain-executor/src/tests.rs index 2e5042273c..585fa80b6b 100644 --- a/domains/client/domain-executor/src/tests.rs +++ b/domains/client/domain-executor/src/tests.rs @@ -1,7 +1,9 @@ use codec::{Decode, Encode}; use domain_runtime_primitives::{DomainCoreApi, Hash}; -use domain_test_service::system_domain_test_runtime::{Address, Header, UncheckedExtrinsic}; -use domain_test_service::Keyring::{Alice, Bob, Ferdie}; +use domain_test_primitives::TimestampApi; +use domain_test_service::evm_domain_test_runtime::{Header, UncheckedExtrinsic}; +use domain_test_service::EcdsaKeyring::{Alice, Bob}; +use domain_test_service::Sr25519Keyring::{self, Ferdie}; use futures::StreamExt; use sc_client_api::{Backend, BlockBackend, HeaderBackend}; use sc_service::{BasePath, Role}; @@ -14,7 +16,7 @@ use sp_core::Pair; use sp_domain_digests::AsPredigest; use sp_domains::fraud_proof::{ExecutionPhase, FraudProof, InvalidStateTransitionProof}; use sp_domains::transaction::InvalidTransactionCode; -use sp_domains::{Bundle, DomainId}; +use sp_domains::{Bundle, DomainId, ExecutorApi}; use sp_runtime::generic::{BlockId, Digest, DigestItem}; use sp_runtime::traits::{BlakeTwo256, Header as HeaderT}; use sp_runtime::OpaqueExtrinsic; @@ -47,13 +49,13 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut primary_node) + .build_evm_node(Role::Authority, &mut primary_node) .await; produce_blocks!(primary_node, alice, 3) @@ -196,23 +198,23 @@ async fn test_domain_tx_propagate() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; - // Run Bob (a system domain full node) - let mut bob = domain_test_service::SystemDomainNodeBuilder::new( + // Run Bob (a evm domain full node) + let mut bob = domain_test_service::DomainNodeBuilder::new( tokio_handle, Bob, BasePath::new(directory.path().join("bob")), ) - .connect_to_system_domain_node(&alice) - .build_with_mock_primary_node(Role::Full, &mut ferdie) + .connect_to_domain_node(alice.addr.clone()) + .build_evm_node(Role::Full, &mut ferdie) .await; produce_blocks!(ferdie, alice, bob, 5).await.unwrap(); @@ -224,7 +226,7 @@ async fn test_domain_tx_propagate() { // Construct and send an extrinsic to bob, as bob is not a authoity node, the extrinsic has // to propagate to alice to get executed bob.construct_and_send_extrinsic(pallet_balances::Call::transfer { - dest: Address::Id(Alice.public().into()), + dest: Alice.to_account_id(), value: 123, }) .await @@ -254,22 +256,22 @@ async fn test_executor_full_node_catching_up() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; - // Run Bob (a system domain full node) - let bob = domain_test_service::SystemDomainNodeBuilder::new( + // Run Bob (a evm domain full node) + let bob = domain_test_service::DomainNodeBuilder::new( tokio_handle, Bob, BasePath::new(directory.path().join("bob")), ) - .build_with_mock_primary_node(Role::Full, &mut ferdie) + .build_evm_node(Role::Full, &mut ferdie) .await; // Bob is able to sync blocks. @@ -290,68 +292,71 @@ async fn test_executor_full_node_catching_up() { } // TODO: Unlock test when evm domain is supported in DecEx v2. -// #[substrate_test_utils::test(flavor = "multi_thread")] -// async fn test_executor_inherent_timestamp_is_set() { -// let directory = TempDir::new().expect("Must be able to create temporary directory"); +#[substrate_test_utils::test(flavor = "multi_thread")] +async fn test_executor_inherent_timestamp_is_set() { + let directory = TempDir::new().expect("Must be able to create temporary directory"); -// let mut builder = sc_cli::LoggerBuilder::new(""); -// builder.with_colors(false); -// let _ = builder.init(); + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_colors(false); + let _ = builder.init(); -// let tokio_handle = tokio::runtime::Handle::current(); + let tokio_handle = tokio::runtime::Handle::current(); -// // Start Ferdie -// let mut ferdie = MockPrimaryNode::run_mock_primary_node( -// tokio_handle.clone(), -// Ferdie, -// BasePath::new(directory.path().join("ferdie")), -// ); + // Start Ferdie + let mut ferdie = MockPrimaryNode::run_mock_primary_node( + tokio_handle.clone(), + Ferdie, + BasePath::new(directory.path().join("ferdie")), + ); -// // Run Alice (a system domain authority node) -// let alice = domain_test_service::SystemDomainNodeBuilder::new( -// tokio_handle.clone(), -// Alice, -// BasePath::new(directory.path().join("alice")), -// ) -// .build_with_mock_primary_node(Role::Authority, &mut ferdie) -// .await; + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( + tokio_handle.clone(), + Alice, + BasePath::new(directory.path().join("alice")), + ) + .build_evm_node(Role::Authority, &mut ferdie) + .await; -// // Run Bob who runs the authority node for core domain -// let bob = domain_test_service::CoreDomainNodeBuilder::new( -// tokio_handle.clone(), -// Bob, -// BasePath::new(directory.path().join("bob")), -// ) -// .build_core_payments_node(Role::Authority, &mut ferdie, &alice) -// .await; + // Run Bob who runs the authority node for core domain + let bob = domain_test_service::DomainNodeBuilder::new( + tokio_handle.clone(), + Bob, + BasePath::new(directory.path().join("bob")), + ) + .build_evm_node(Role::Authority, &mut ferdie) + .await; -// produce_blocks!(ferdie, alice, bob, 1).await.unwrap(); + produce_blocks!(ferdie, alice, bob, 1).await.unwrap(); -// let primary_api = ferdie.client.runtime_api(); -// let primary_timestamp = primary_api -// .timestamp(ferdie.client.info().best_hash) -// .unwrap(); + let primary_api = ferdie.client.runtime_api(); + let primary_timestamp = primary_api + .timestamp(ferdie.client.info().best_hash) + .unwrap(); -// let core_api = bob.client.runtime_api(); -// let core_timestamp = core_api.timestamp(bob.client.info().best_hash).unwrap(); + let core_api = bob.client.runtime_api(); + let core_timestamp = core_api.timestamp(bob.client.info().best_hash).unwrap(); -// assert_eq!( -// primary_timestamp, core_timestamp, -// "Timestamp should be preset on Core domain and should match Primary runtime timestamp" -// ); -// } + assert_eq!( + primary_timestamp, core_timestamp, + "Timestamp should be preset on Core domain and should match Primary runtime timestamp" + ); +} #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn test_initialize_block_proof_creation_and_verification_should_work() { test_invalid_state_transition_proof_creation_and_verification(0).await } #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn test_apply_extrinsic_proof_creation_and_verification_should_work() { test_invalid_state_transition_proof_creation_and_verification(1).await } #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn test_finalize_block_proof_creation_and_verification_should_work() { test_invalid_state_transition_proof_creation_and_verification(2).await } @@ -377,13 +382,13 @@ async fn test_invalid_state_transition_proof_creation_and_verification( BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let mut alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let mut alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; let bundle_to_tx = |opaque_bundle| { @@ -397,7 +402,7 @@ async fn test_invalid_state_transition_proof_creation_and_verification( alice .construct_and_send_extrinsic(pallet_balances::Call::transfer { - dest: Address::Id(Bob.public().into()), + dest: Bob.to_account_id(), value: 1, }) .await @@ -436,8 +441,7 @@ async fn test_invalid_state_transition_proof_creation_and_verification( assert_eq!(receipt.trace.len(), 3); receipt.trace[mismatch_trace_index] = Default::default(); - opaque_bundle.sealed_header.signature = alice - .key + opaque_bundle.sealed_header.signature = Sr25519Keyring::Alice .pair() .sign(opaque_bundle.sealed_header.pre_hash().as_ref()) .into(); @@ -504,6 +508,7 @@ async fn test_invalid_state_transition_proof_creation_and_verification( } #[substrate_test_utils::test(flavor = "multi_thread")] +#[ignore] async fn fraud_proof_verification_in_tx_pool_should_work() { let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -520,13 +525,13 @@ async fn fraud_proof_verification_in_tx_pool_should_work() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; // TODO: test the `initialize_block` fraud proof of block 1 with `wait_for_blocks(1)` @@ -617,7 +622,7 @@ async fn fraud_proof_verification_in_tx_pool_should_work() { let parent_number_ferdie = *parent_header_ferdie.number(); let good_invalid_state_transition_proof = InvalidStateTransitionProof { - domain_id: DomainId::SYSTEM, + domain_id: DomainId::new(3u32), bad_receipt_hash: bad_receipt.hash(), parent_number: parent_number_ferdie, primary_parent_hash: parent_hash_ferdie, @@ -692,13 +697,13 @@ async fn set_new_code_should_work() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; produce_blocks!(ferdie, alice, 1).await.unwrap(); @@ -763,22 +768,22 @@ async fn pallet_domains_unsigned_extrinsics_should_work() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; - // Run Bob (a system domain full node) - let bob = domain_test_service::SystemDomainNodeBuilder::new( + // Run Bob (a evm domain full node) + let bob = domain_test_service::DomainNodeBuilder::new( tokio_handle, Bob, BasePath::new(directory.path().join("bob")), ) - .build_with_mock_primary_node(Role::Full, &mut ferdie) + .build_evm_node(Role::Full, &mut ferdie) .await; produce_blocks!(ferdie, alice, 1).await.unwrap(); @@ -786,7 +791,7 @@ async fn pallet_domains_unsigned_extrinsics_should_work() { // Get a bundle from alice's tx pool and used as bundle template. let (_, bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; let bundle_template = bundle.unwrap(); - let alice_key = alice.key; + let alice_key = Sr25519Keyring::Alice; // Drop alice in order to control the execution chain by submitting the receipts manually later. drop(alice); @@ -826,7 +831,7 @@ async fn pallet_domains_unsigned_extrinsics_should_work() { let best_hash = ferdie_client.info().best_hash; ferdie_client .runtime_api() - .head_receipt_number(best_hash, DomainId::SYSTEM) + .head_receipt_number(best_hash, DomainId::new(3u32)) .expect("Failed to get head receipt number") }; @@ -840,42 +845,6 @@ async fn pallet_domains_unsigned_extrinsics_should_work() { .unwrap(); produce_blocks!(ferdie, bob, 1).await.unwrap(); assert_eq!(head_receipt_number(), 2); - - // max drift is 2, hence the max allowed receipt number is 2 + 2, 5 will be rejected as being - // too far. - match ferdie - .submit_transaction(create_submit_bundle(5)) - .await - .unwrap_err() - { - sc_transaction_pool::error::Error::Pool( - sc_transaction_pool_api::error::Error::InvalidTransaction(invalid_tx), - ) => assert_eq!(invalid_tx, InvalidTransactionCode::ExecutionReceipt.into()), - e => panic!("Unexpected error while submitting execution receipt: {e}"), - } - - // The 4 is able to be submitted to tx pool but the execution will fail as the receipt of 3 is missing. - let submit_bundle_4 = create_submit_bundle(4); - ferdie - .submit_transaction(submit_bundle_4.clone()) - .await - .unwrap(); - assert!(ferdie.produce_blocks(1).await.is_err()); - assert_eq!(head_receipt_number(), 2); - - // Re-submit 4 after 3, this time the execution will succeed and the head receipt number will - // be updated. - ferdie.prune_tx_from_pool(&submit_bundle_4).await.unwrap(); - ferdie - .submit_transaction(create_submit_bundle(3)) - .await - .unwrap(); - ferdie - .submit_transaction(create_submit_bundle(4)) - .await - .unwrap(); - produce_blocks!(ferdie, bob, 1).await.unwrap(); - assert_eq!(head_receipt_number(), 4); } #[substrate_test_utils::test(flavor = "multi_thread")] @@ -895,13 +864,13 @@ async fn duplicated_and_stale_bundle_should_be_rejected() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; produce_blocks!(ferdie, alice, 1).await.unwrap(); @@ -971,13 +940,13 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { BasePath::new(directory.path().join("ferdie")), ); - // Run Alice (a system domain authority node) - let alice = domain_test_service::SystemDomainNodeBuilder::new( + // Run Alice (a evm domain authority node) + let alice = domain_test_service::DomainNodeBuilder::new( tokio_handle.clone(), Alice, BasePath::new(directory.path().join("alice")), ) - .build_with_mock_primary_node(Role::Authority, &mut ferdie) + .build_evm_node(Role::Authority, &mut ferdie) .await; produce_blocks!(ferdie, alice, 3).await.unwrap(); @@ -1023,7 +992,7 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { } } -// TODO: Unlock test when fixed (core-eth-relay was removed) +// TODO: Unlock test when multiple domains are supported in DecEx v2. // #[substrate_test_utils::test(flavor = "multi_thread")] // async fn test_cross_domains_message_should_work() { // let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -1042,17 +1011,17 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { // ); // // // Run Alice (a system domain authority node) -// let mut alice = domain_test_service::SystemDomainNodeBuilder::new( +// let mut alice = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Alice, // BasePath::new(directory.path().join("alice")), // ) // .run_relayer() -// .build_with_mock_primary_node(Role::Authority, &mut ferdie) +// .build_evm_node(Role::Authority, &mut ferdie) // .await; // // // Run Bob (a core payments domain authority node) -// let mut bob = domain_test_service::CoreDomainNodeBuilder::new( +// let mut bob = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Bob, // BasePath::new(directory.path().join("bob")), @@ -1062,7 +1031,7 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { // .await; // // // Run Charlie (a core eth relay domain authority node) -// let mut charlie = domain_test_service::CoreDomainNodeBuilder::new( +// let mut charlie = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Charlie, // BasePath::new(directory.path().join("charlie")), @@ -1225,17 +1194,17 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { // ); // // Run Alice (a system domain authority node) -// let mut alice = domain_test_service::SystemDomainNodeBuilder::new( +// let mut alice = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Alice, // BasePath::new(directory.path().join("alice")), // ) // .run_relayer() -// .build_with_mock_primary_node(Role::Authority, &mut ferdie) +// .build_evm_node(Role::Authority, &mut ferdie) // .await; // // Run Bob (a core payments domain authority node) -// let mut bob = domain_test_service::CoreDomainNodeBuilder::new( +// let mut bob = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Bob, // BasePath::new(directory.path().join("bob")), @@ -1245,7 +1214,7 @@ async fn existing_bundle_can_be_resubmitted_to_new_fork() { // .await; // // Run Charlie (a core eth relay domain full node) and don't its relayer worker -// let charlie = domain_test_service::CoreDomainNodeBuilder::new( +// let charlie = domain_test_service::DomainNodeBuilder::new( // tokio_handle.clone(), // Charlie, // BasePath::new(directory.path().join("charlie")), From 42c04acdbe15f5e09031b19c5fe31f0875e3fe23 Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 29 Jun 2023 14:10:00 +0800 Subject: [PATCH 3/4] Apply review suggection Signed-off-by: linning --- domains/test/service/src/domain.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domains/test/service/src/domain.rs b/domains/test/service/src/domain.rs index 462838eecd..9d56d6c21c 100644 --- a/domains/test/service/src/domain.rs +++ b/domains/test/service/src/domain.rs @@ -92,6 +92,8 @@ where { /// The domain id pub domain_id: DomainId, + // TODO: Make the signing scheme generic over domains, because Ecdsa only used in the EVM domain, + // other (incoming) domains may use Sr25519 /// The node's account key pub key: EcdsaKeyring, /// TaskManager's instance. From a491acc00ec9689b53008eaa6aa27a5342201665 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 29 Jun 2023 11:54:36 +0300 Subject: [PATCH 4/4] Update code owners --- .github/CODEOWNERS | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2f3046cb9a..2c4c0e3b03 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,14 +2,17 @@ # below ones takes precedence over the upper ones # Global owners -* @nazar-pc @rg3l3dr +* @nazar-pc @rg3l3dr -/crates @liuchengxu @nazar-pc @rg3l3dr -/crates/pallet-* @liuchengxu @nazar-pc @rg3l3dr @vedhavyas -/crates/sp-* @liuchengxu @nazar-pc @rg3l3dr @vedhavyas -/crates/subspace-archiving @liuchengxu @i1i1 @nazar-pc @rg3l3dr -/crates/subspace-farmer @i1i1 @nazar-pc @rg3l3dr -/crates/subspace-networking @nazar-pc @rg3l3dr @shamil-gadelshin -/crates/subspace-runtime* @liuchengxu @nazar-pc @rg3l3dr @vedhavyas -/crates/subspace-solving @i1i1 @liuchengxu @nazar-pc @rg3l3dr -/crates/substrate @nazar-pc @rg3l3dr +/crates @liuchengxu @nazar-pc @rg3l3dr +/crates/pallet-* @liuchengxu @nazar-pc @rg3l3dr @vedhavyas @NingLin-P +/crates/sp-* @liuchengxu @nazar-pc @rg3l3dr @vedhavyas @NingLin-P +/crates/subspace-archiving @liuchengxu @shamil-gadelshin @nazar-pc @rg3l3dr +/crates/subspace-farmer @nazar-pc @shamil-gadelshin @rg3l3dr +/crates/subspace-networking @shamil-gadelshin @nazar-pc @rg3l3dr +/crates/subspace-runtime* @liuchengxu @vedhavyas @nazar-pc @rg3l3dr +/crates/subspace-node @NingLin-P @nazar-pc @rg3l3dr +/crates/subspace-fraud-proof @NingLin-P @nazar-pc @rg3l3dr +/crates/subspace-transaction-pool @NingLin-P @nazar-pc @rg3l3dr +/crates/substrate @nazar-pc @rg3l3dr +/domains @liuchengxu @vedhavyas @NingLin-P @nazar-pc @rg3l3dr