diff --git a/operator/Cargo.lock b/operator/Cargo.lock index e95ea0df..cb657001 100644 --- a/operator/Cargo.lock +++ b/operator/Cargo.lock @@ -483,6 +483,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1345,6 +1354,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -1540,17 +1558,31 @@ version = "0.1.0" dependencies = [ "clap", "datahaven-runtime", + "fc-cli", + "fc-consensus", + "fc-db", + "fc-mapping-sync", + "fc-rpc", + "fc-rpc-core", + "fc-storage", + "flume 0.10.14", "fp-account", + "fp-evm", + "fp-rpc", "frame-benchmarking-cli", "frame-metadata-hash-extension", "frame-system", + "frame-system-rpc-runtime-api", "futures", "hex-literal 0.3.4", "jsonrpsee", "mmr-rpc", + "pallet-ethereum", "pallet-im-online", "pallet-transaction-payment", "pallet-transaction-payment-rpc", + "pallet-transaction-payment-rpc-runtime-api", + "parity-scale-codec", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -1561,6 +1593,7 @@ dependencies = [ "sc-consensus-grandpa", "sc-executor", "sc-network", + "sc-network-sync", "sc-offchain", "sc-rpc", "sc-service", @@ -1578,10 +1611,14 @@ dependencies = [ "sp-inherents", "sp-io", "sp-keyring", + "sp-offchain", "sp-runtime", + "sp-session", "sp-timestamp", + "sp-transaction-pool", "substrate-build-script-utils", "substrate-frame-rpc-system", + "url", ] [[package]] @@ -1590,6 +1627,9 @@ version = "0.1.0" dependencies = [ "datahaven-runtime-common", "fp-account", + "fp-evm", + "fp-rpc", + "fp-self-contained", "frame-benchmarking", "frame-executive", "frame-metadata-hash-extension", @@ -1875,6 +1915,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "downcast" version = "0.11.0" @@ -1974,6 +2020,9 @@ name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] [[package]] name = "elliptic-curve" @@ -2277,6 +2326,187 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fc-api" +version = "1.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "async-trait", + "fp-storage", + "parity-scale-codec", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "fc-cli" +version = "1.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "clap", + "ethereum-types", + "fc-db", + "fp-rpc", + "fp-storage", + "sc-cli", + "serde", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "fc-consensus" +version = "2.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "async-trait", + "fp-consensus", + "fp-rpc", + "sc-consensus", + "sp-api", + "sp-block-builder", + "sp-consensus", + "sp-runtime", + "thiserror 1.0.69", +] + +[[package]] +name = "fc-db" +version = "2.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "async-trait", + "ethereum", + "fc-api", + "fc-storage", + "fp-consensus", + "fp-rpc", + "fp-storage", + "futures", + "kvdb-rocksdb", + "log", + "parity-db", + "parity-scale-codec", + "parking_lot 0.12.3", + "sc-client-api", + "sc-client-db", + "smallvec", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-database", + "sp-runtime", + "sqlx", + "tokio", +] + +[[package]] +name = "fc-mapping-sync" +version = "2.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "fc-db", + "fc-storage", + "fp-consensus", + "fp-rpc", + "futures", + "futures-timer", + "log", + "parking_lot 0.12.3", + "sc-client-api", + "sc-utils", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "tokio", +] + +[[package]] +name = "fc-rpc" +version = "2.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "ethereum", + "ethereum-types", + "evm", + "fc-api", + "fc-mapping-sync", + "fc-rpc-core", + "fc-storage", + "fp-evm", + "fp-rpc", + "fp-storage", + "futures", + "hex", + "jsonrpsee", + "libsecp256k1", + "log", + "pallet-evm", + "parity-scale-codec", + "prometheus", + "rand", + "rlp", + "sc-client-api", + "sc-network", + "sc-network-sync", + "sc-rpc", + "sc-service", + "sc-transaction-pool", + "sc-transaction-pool-api", + "sc-utils", + "schnellru", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-storage", + "substrate-prometheus-endpoint", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "fc-rpc-core" +version = "1.1.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "ethereum", + "ethereum-types", + "jsonrpsee", + "rlp", + "rustc-hex", + "serde", + "serde_json", + "sp-crypto-hashing", +] + +[[package]] +name = "fc-storage" +version = "1.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-rpc", + "fp-storage", + "parity-scale-codec", + "sc-client-api", + "sp-api", + "sp-io", + "sp-runtime", + "sp-storage", +] + [[package]] name = "fdlimit" version = "0.3.0" @@ -2378,6 +2608,30 @@ dependencies = [ "num-traits", ] +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin 0.9.8", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2506,6 +2760,18 @@ dependencies = [ "sp-state-machine", ] +[[package]] +name = "fp-self-contained" +version = "1.0.0-dev" +source = "git+https://github.com/polkadot-evm/frontier?branch=stable2409#a012990acd6f9ecd90c15e63abbb3f12704c4bd8" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", +] + [[package]] name = "fp-storage" version = "2.0.0" @@ -2883,6 +3149,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.3", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -3002,8 +3279,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -3219,6 +3498,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "heck" @@ -4614,6 +4896,17 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -5238,6 +5531,32 @@ dependencies = [ "rand", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "netlink-packet-core" version = "0.7.0" @@ -7517,7 +7836,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted 0.7.1", "web-sys", "winapi", @@ -10206,6 +10525,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.3.0" @@ -10225,6 +10553,126 @@ dependencies = [ "der", ] +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 2.5.3", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.8.0", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "sha2 0.10.8", + "smallvec", + "sqlformat", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +dependencies = [ + "dotenvy", + "either", + "heck 0.4.1", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "sqlx-core", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "flume 0.11.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + [[package]] name = "ss58-registry" version = "1.51.0" @@ -11225,6 +11673,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.5.1" @@ -11280,6 +11734,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" diff --git a/operator/Cargo.toml b/operator/Cargo.toml index bbf8f432..22fd0d92 100644 --- a/operator/Cargo.toml +++ b/operator/Cargo.toml @@ -25,6 +25,7 @@ async-trait = { version = "0.1.42" } blake2-rfc = { version = "0.2.18", default-features = false } clap = { version = "4.5.10" } codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" } +flume = "0.10.9" futures = { version = "0.3.30" } hex = { version = "0.4.3", default-features = false } hex-literal = { version = "0.3.4" } @@ -37,6 +38,7 @@ scale-info = { version = "2.11.6", default-features = false} serde = { version = "1.0.197", default-features = false, features = [ "derive" ]} serde_json = { version = "1.0.127", default-features = false } sha3 = { version = "0.10", default-features = false } +url = "2.2.2" # Polkadot frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } @@ -76,6 +78,7 @@ sc-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk", branch sc-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } sc-executor = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } sc-network = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } +sc-network-sync = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } sc-offchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } sc-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } @@ -122,6 +125,25 @@ snowbridge-pallet-ethereum-client = { git = "https://github.com/paritytech/polka # Frontier (wasm) fp-account = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fp-evm = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fp-rpc = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fp-self-contained = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fp-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +pallet-base-fee = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +pallet-dynamic-fee = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } pallet-ethereum = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2409", default-features = false } pallet-evm = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2409", default-features = false } pallet-evm-chain-id = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2409", default-features = false } +pallet-evm-precompile-modexp = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +pallet-evm-precompile-sha3fips = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +pallet-hotfix-sufficients = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } + +# Frontier (client) +fc-cli = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fc-consensus = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fc-db = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409" } +fc-mapping-sync = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fc-rpc = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fc-rpc-core = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } +fc-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2409", default-features = false } diff --git a/operator/node/Cargo.toml b/operator/node/Cargo.toml index 5d036306..a3ac9b7e 100644 --- a/operator/node/Cargo.toml +++ b/operator/node/Cargo.toml @@ -16,18 +16,22 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { features = ["derive"], workspace = true } +codec = { workspace = true } datahaven-runtime.workspace = true +flume = { workspace = true } fp-account = { workspace = true } frame-benchmarking-cli.default-features = true frame-benchmarking-cli.workspace = true frame-metadata-hash-extension.default-features = true frame-metadata-hash-extension.workspace = true +frame-system-rpc-runtime-api = { workspace = true } frame-system.default-features = true frame-system.workspace = true futures = { features = ["thread-pool"], workspace = true } hex-literal.workspace = true jsonrpsee = { features = ["server"], workspace = true } pallet-im-online.workspace = true +pallet-transaction-payment-rpc-runtime-api = { workspace = true, features = ["std"] } pallet-transaction-payment-rpc.default-features = true pallet-transaction-payment-rpc.workspace = true pallet-transaction-payment.default-features = true @@ -46,6 +50,7 @@ sc-consensus.default-features = true sc-consensus.workspace = true sc-executor.default-features = true sc-executor.workspace = true +sc-network-sync.workspace = true sc-network.default-features = true sc-network.workspace = true sc-offchain.default-features = true @@ -79,12 +84,16 @@ sp-io.default-features = true sp-io.workspace = true sp-keyring.default-features = true sp-keyring.workspace = true +sp-offchain = { workspace = true, features = ["default"] } sp-runtime.default-features = true sp-runtime.workspace = true +sp-session = { workspace = true, features = ["default"] } sp-timestamp.default-features = true sp-timestamp.workspace = true +sp-transaction-pool = { workspace = true, features = ["default"] } substrate-frame-rpc-system.default-features = true substrate-frame-rpc-system.workspace = true +url = { workspace = true } # RPC sc-rpc = { workspace = true, default-features = true } @@ -97,6 +106,18 @@ sc-consensus-beefy.workspace = true # MMR mmr-rpc = { workspace = true, default-features = true } +# Frontier +fc-cli = { workspace = true } +fc-consensus = { workspace = true } +fc-db = { workspace = true } +fc-mapping-sync = { workspace = true, features = ["sql"] } +fc-rpc = { workspace = true } +fc-rpc-core = { workspace = true } +fc-storage = { workspace = true } +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +pallet-ethereum = { workspace = true } + [build-dependencies] substrate-build-script-utils.default-features = true substrate-build-script-utils.workspace = true @@ -104,21 +125,22 @@ substrate-build-script-utils.workspace = true [features] default = ["std"] std = [ - "datahaven-runtime/std", + "datahaven-runtime/std", ] + # Dependencies that are only required if runtime benchmarking should be build. runtime-benchmarks = [ - "frame-benchmarking-cli/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "datahaven-runtime/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "datahaven-runtime/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = [ - "frame-system/try-runtime", - "pallet-transaction-payment/try-runtime", - "datahaven-runtime/try-runtime", - "sp-runtime/try-runtime", + "frame-system/try-runtime", + "pallet-transaction-payment/try-runtime", + "datahaven-runtime/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/operator/node/src/cli.rs b/operator/node/src/cli.rs index 72d44652..2ee5e6ab 100644 --- a/operator/node/src/cli.rs +++ b/operator/node/src/cli.rs @@ -1,12 +1,30 @@ +use crate::eth::EthConfiguration; use sc_cli::RunCmd; +// Available Sealing methods. +#[derive(Copy, Clone, Debug, Default, clap::ValueEnum)] +pub enum Sealing { + /// Seal using rpc method. + #[default] + Manual, + /// Seal when transaction is executed. + Instant, +} #[derive(Debug, clap::Parser)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, - #[clap(flatten)] + #[allow(missing_docs)] + #[command(flatten)] pub run: RunCmd, + + /// Choose sealing method. + #[arg(long, value_enum, ignore_case = true)] + pub sealing: Option, + + #[command(flatten)] + pub eth: EthConfiguration, } #[derive(Debug, clap::Subcommand)] diff --git a/operator/node/src/client.rs b/operator/node/src/client.rs new file mode 100644 index 00000000..6617c1b6 --- /dev/null +++ b/operator/node/src/client.rs @@ -0,0 +1,62 @@ +use crate::eth::EthCompatRuntimeApiCollection; +use codec::Codec; +// Substrate +use datahaven_runtime::{AccountId, Nonce}; +use sc_executor::WasmExecutor; +use sp_runtime::traits::{Block as BlockT, MaybeDisplay}; + +/// Full backend. +pub type FullBackend = sc_service::TFullBackend; +/// Full client. +pub type FullClient = sc_service::TFullClient>; + +/// A set of APIs that every runtime must implement. +pub trait _BaseRuntimeApiCollection: + sp_api::ApiExt + + sp_api::Metadata + + sp_block_builder::BlockBuilder + + sp_offchain::OffchainWorkerApi + + sp_session::SessionKeys + + sp_transaction_pool::runtime_api::TaggedTransactionQueue +{ +} + +impl _BaseRuntimeApiCollection for Api +where + Block: BlockT, + Api: sp_api::ApiExt + + sp_api::Metadata + + sp_block_builder::BlockBuilder + + sp_offchain::OffchainWorkerApi + + sp_session::SessionKeys + + sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ +} + +/// A set of APIs that template runtime must implement. +pub trait _RuntimeApiCollection: + _BaseRuntimeApiCollection + + EthCompatRuntimeApiCollection + + sp_consensus_babe::BabeApi + + sp_consensus_grandpa::GrandpaApi + + frame_system_rpc_runtime_api::AccountNonceApi + + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::EthereumRuntimeRPCApi +{ +} + +impl _RuntimeApiCollection for Api +where + Block: BlockT, + Balance: Codec + MaybeDisplay, + Api: _BaseRuntimeApiCollection + + EthCompatRuntimeApiCollection + + sp_consensus_babe::BabeApi + + sp_consensus_grandpa::GrandpaApi + + frame_system_rpc_runtime_api::AccountNonceApi + + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::EthereumRuntimeRPCApi, +{ +} diff --git a/operator/node/src/command.rs b/operator/node/src/command.rs index f6e43c6e..76807daa 100644 --- a/operator/node/src/command.rs +++ b/operator/node/src/command.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use crate::service::frontier_database_dir; use crate::{ benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, chain_spec::{self, alith}, @@ -9,7 +10,7 @@ use crate::{ use datahaven_runtime::{Block, EXISTENTIAL_DEPOSIT}; use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; use sc_cli::SubstrateCli; -use sc_service::PartialComponents; +use sc_service::{DatabaseSource, PartialComponents}; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -65,7 +66,7 @@ pub fn run() -> sc_cli::Result<()> { task_manager, import_queue, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; Ok((cmd.run(client, import_queue), task_manager)) }) } @@ -76,7 +77,7 @@ pub fn run() -> sc_cli::Result<()> { client, task_manager, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; Ok((cmd.run(client, config.database), task_manager)) }) } @@ -87,7 +88,7 @@ pub fn run() -> sc_cli::Result<()> { client, task_manager, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; Ok((cmd.run(client, config.chain_spec), task_manager)) }) } @@ -99,13 +100,28 @@ pub fn run() -> sc_cli::Result<()> { task_manager, import_queue, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; Ok((cmd.run(client, import_queue), task_manager)) }) } Some(Subcommand::PurgeChain(cmd)) => { let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| cmd.run(config.database)) + runner.sync_run(|config| { + // Remove Frontier offchain db + let frontier_database_config = match config.database { + DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb { + path: frontier_database_dir(&config, "db"), + cache_size: 0, + }, + DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb { + path: frontier_database_dir(&config, "paritydb"), + }, + _ => { + return Err(format!("Cannot purge `{:?}` database", config.database).into()) + } + }; + cmd.run(frontier_database_config) + }) } Some(Subcommand::Revert(cmd)) => { let runner = cli.create_runner(cmd)?; @@ -115,7 +131,7 @@ pub fn run() -> sc_cli::Result<()> { task_manager, backend, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; let aux_revert = Box::new(|client: Arc, backend, blocks| { sc_consensus_babe::revert(client.clone(), backend, blocks)?; sc_consensus_grandpa::revert(client, blocks)?; @@ -145,7 +161,8 @@ pub fn run() -> sc_cli::Result<()> { )) } BenchmarkCmd::Block(cmd) => { - let PartialComponents { client, .. } = service::new_partial(&config)?; + let PartialComponents { client, .. } = + service::new_partial(&config, &mut cli.eth.clone())?; cmd.run(client) } #[cfg(not(feature = "runtime-benchmarks"))] @@ -157,14 +174,15 @@ pub fn run() -> sc_cli::Result<()> { BenchmarkCmd::Storage(cmd) => { let PartialComponents { client, backend, .. - } = service::new_partial(&config)?; + } = service::new_partial(&config, &mut cli.eth.clone())?; let db = backend.expose_db(); let storage = backend.expose_storage(); cmd.run(config, client, db, storage) } BenchmarkCmd::Overhead(cmd) => { - let PartialComponents { client, .. } = service::new_partial(&config)?; + let PartialComponents { client, .. } = + service::new_partial(&config, &mut cli.eth.clone())?; let ext_builder = RemarkBuilder::new(client.clone()); cmd.run( @@ -176,7 +194,8 @@ pub fn run() -> sc_cli::Result<()> { ) } BenchmarkCmd::Extrinsic(cmd) => { - let PartialComponents { client, .. } = service::new_partial(&config)?; + let PartialComponents { client, .. } = + service::new_partial(&config, &mut cli.eth.clone())?; // Register the *Remark* and *TKA* builders. let ext_factory = ExtrinsicFactory(vec![ Box::new(RemarkBuilder::new(client.clone())), @@ -208,10 +227,15 @@ pub fn run() -> sc_cli::Result<()> { datahaven_runtime::opaque::Block, ::Hash, >, - >(config) + >( + config, cli.eth + ) + .await .map_err(sc_cli::Error::Service), + sc_network::config::NetworkBackendType::Litep2p => { - service::new_full::(config) + service::new_full::(config, cli.eth) + .await .map_err(sc_cli::Error::Service) } } diff --git a/operator/node/src/eth.rs b/operator/node/src/eth.rs new file mode 100644 index 00000000..50c6311d --- /dev/null +++ b/operator/node/src/eth.rs @@ -0,0 +1,232 @@ +use std::{ + collections::BTreeMap, + sync::{Arc, Mutex}, + time::Duration, +}; + +use fc_rpc::EthTask; +pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool}; +pub use fc_storage::{StorageOverride, StorageOverrideHandler}; +use fp_rpc::EthereumRuntimeRPCApi; +use futures::{future, prelude::*}; +// Substrate +use sc_client_api::BlockchainEvents; +use sc_executor::HostFunctions; +use sc_network_sync::SyncingService; +use sc_service::{error::Error as ServiceError, TaskManager}; +use sp_api::ConstructRuntimeApi; +use sp_core::H256; +use sp_runtime::traits::Block as BlockT; + +use crate::client::{FullBackend, FullClient}; + +/// Frontier DB backend type. +pub type FrontierBackend = fc_db::Backend; + +/// Available frontier backend types. +#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)] +pub enum BackendType { + /// Either RocksDb or ParityDb as per inherited from the global backend settings. + #[default] + KeyValue, + /// Sql database with custom log indexing. + Sql, +} + +/// The ethereum-compatibility configuration used to run a node. +#[derive(Clone, Debug, clap::Parser)] +pub struct EthConfiguration { + /// Maximum number of logs in a query. + #[arg(long, default_value = "10000")] + pub max_past_logs: u32, + + /// Maximum fee history cache size. + #[arg(long, default_value = "2048")] + pub fee_history_limit: u64, + + #[arg(long)] + pub enable_dev_signer: bool, + + /// The dynamic-fee pallet target gas price set by block author + #[arg(long, default_value = "1")] + pub target_gas_price: u64, + + /// Maximum allowed gas limit will be `block.gas_limit * execute_gas_limit_multiplier` + /// when using eth_call/eth_estimateGas. + #[arg(long, default_value = "10")] + pub execute_gas_limit_multiplier: u64, + + /// Size in bytes of the LRU cache for block data. + #[arg(long, default_value = "50")] + pub eth_log_block_cache: usize, + + /// Size in bytes of the LRU cache for transactions statuses data. + #[arg(long, default_value = "50")] + pub eth_statuses_cache: usize, + + /// Sets the frontier backend type (KeyValue or Sql) + #[arg(long, value_enum, ignore_case = true, default_value_t = BackendType::default())] + pub frontier_backend_type: BackendType, + + // Sets the SQL backend's pool size. + #[arg(long, default_value = "100")] + pub frontier_sql_backend_pool_size: u32, + + /// Sets the SQL backend's query timeout in number of VM ops. + #[arg(long, default_value = "10000000")] + pub frontier_sql_backend_num_ops_timeout: u32, + + /// Sets the SQL backend's auxiliary thread limit. + #[arg(long, default_value = "4")] + pub frontier_sql_backend_thread_count: u32, + + /// Sets the SQL backend's query timeout in number of VM ops. + /// Default value is 200MB. + #[arg(long, default_value = "209715200")] + pub frontier_sql_backend_cache_size: u64, +} + +pub struct FrontierPartialComponents { + pub filter_pool: Option, + pub fee_history_cache: FeeHistoryCache, + pub fee_history_cache_limit: FeeHistoryCacheLimit, +} + +pub fn new_frontier_partial( + config: &EthConfiguration, +) -> Result { + Ok(FrontierPartialComponents { + filter_pool: Some(Arc::new(Mutex::new(BTreeMap::new()))), + fee_history_cache: Arc::new(Mutex::new(BTreeMap::new())), + fee_history_cache_limit: config.fee_history_limit, + }) +} + +/// A set of APIs that ethereum-compatible runtimes must implement. +pub trait EthCompatRuntimeApiCollection: + sp_api::ApiExt + fp_rpc::ConvertTransactionRuntimeApi + EthereumRuntimeRPCApi +{ +} + +impl EthCompatRuntimeApiCollection for Api +where + Block: BlockT, + Api: sp_api::ApiExt + + fp_rpc::ConvertTransactionRuntimeApi + + EthereumRuntimeRPCApi, +{ +} + +pub struct FrontierTasksParams +where + B: BlockT, + RA: ConstructRuntimeApi>, + RA: Send + Sync + 'static, + RA::RuntimeApi: EthCompatRuntimeApiCollection, + HF: HostFunctions + 'static, +{ + pub client: Arc>, + pub backend: Arc>, + pub frontier_backend: Arc>>, + pub frontier_partial_components: FrontierPartialComponents, + pub storage_override: Arc>, + pub sync: Arc>, + pub pubsub_notification_sinks: Arc< + fc_mapping_sync::EthereumBlockNotificationSinks< + fc_mapping_sync::EthereumBlockNotification, + >, + >, +} + +pub async fn spawn_frontier_tasks( + task_manager: &TaskManager, + params: FrontierTasksParams, +) where + B: BlockT, + RA: ConstructRuntimeApi>, + RA: Send + Sync + 'static, + RA::RuntimeApi: EthCompatRuntimeApiCollection, + HF: HostFunctions + 'static, +{ + let FrontierTasksParams { + client, + backend, + frontier_backend, + frontier_partial_components, + storage_override, + sync, + pubsub_notification_sinks, + } = params; + + let FrontierPartialComponents { + filter_pool, + fee_history_cache, + fee_history_cache_limit, + } = frontier_partial_components; + + // Spawn main mapping sync worker background task. + match &*frontier_backend { + fc_db::Backend::KeyValue(b) => { + task_manager.spawn_essential_handle().spawn( + "frontier-mapping-sync-worker", + Some("frontier"), + fc_mapping_sync::kv::MappingSyncWorker::new( + client.import_notification_stream(), + Duration::new(6, 0), + client.clone(), + backend, + storage_override.clone(), + b.clone(), + 3, + 0u32.into(), + fc_mapping_sync::SyncStrategy::Normal, + sync, + pubsub_notification_sinks, + ) + .for_each(|()| future::ready(())), + ); + } + fc_db::Backend::Sql(b) => { + task_manager.spawn_essential_handle().spawn_blocking( + "frontier-mapping-sync-worker", + Some("frontier"), + fc_mapping_sync::sql::SyncWorker::run( + client.clone(), + backend, + b.clone(), + client.import_notification_stream(), + fc_mapping_sync::sql::SyncWorkerConfig { + read_notification_timeout: Duration::from_secs(30), + check_indexed_blocks_interval: Duration::from_secs(60), + }, + fc_mapping_sync::SyncStrategy::Parachain, + sync, + pubsub_notification_sinks, + ), + ); + } + } + + // Spawn Frontier EthFilterApi maintenance task. + if let Some(filter_pool) = filter_pool { + // Each filter is allowed to stay in the pool for 100 blocks. + const FILTER_RETAIN_THRESHOLD: u64 = 100; + task_manager.spawn_essential_handle().spawn( + "frontier-filter-pool", + Some("frontier"), + EthTask::filter_pool_task(client.clone(), filter_pool, FILTER_RETAIN_THRESHOLD), + ); + } + + // Spawn Frontier FeeHistory cache maintenance task. + task_manager.spawn_essential_handle().spawn( + "frontier-fee-history", + Some("frontier"), + EthTask::fee_history_task( + client, + storage_override, + fee_history_cache, + fee_history_cache_limit, + ), + ); +} diff --git a/operator/node/src/main.rs b/operator/node/src/main.rs index 2149818f..c6131a2d 100644 --- a/operator/node/src/main.rs +++ b/operator/node/src/main.rs @@ -4,7 +4,9 @@ mod benchmarking; mod chain_spec; mod cli; +mod client; mod command; +mod eth; mod rpc; mod service; diff --git a/operator/node/src/service.rs b/operator/node/src/service.rs index 3137bee3..6ddfc7ed 100644 --- a/operator/node/src/service.rs +++ b/operator/node/src/service.rs @@ -1,22 +1,35 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. +use crate::eth::{ + new_frontier_partial, spawn_frontier_tasks, BackendType, FrontierPartialComponents, + FrontierTasksParams, +}; +use crate::eth::{EthConfiguration, StorageOverrideHandler}; use crate::rpc::BeefyDeps; use datahaven_runtime::{self, apis::RuntimeApi, opaque::Block}; +use fc_consensus::FrontierBlockImport; +use fc_db::DatabaseSource; +use fc_storage::StorageOverride; use futures::FutureExt; -use sc_client_api::{Backend, BlockBackend}; +use sc_client_api::{AuxStore, Backend, BlockBackend, StateBackend, StorageProvider}; use sc_consensus_babe::ImportQueueParams; use sc_consensus_grandpa::SharedVoterState; -use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncConfig}; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_network_sync::WarpSyncConfig; +use sc_service::{error::Error as ServiceError, Configuration, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus_beefy::ecdsa_crypto; -use std::{sync::Arc, time::Duration}; +use sp_runtime::traits::BlakeTwo256; +use std::time::Duration; +use std::{path::Path, sync::Arc}; + +pub type HostFunctions = sp_io::SubstrateHostFunctions; + +pub(crate) type FullClient = TFullClient>; -pub(crate) type FullClient = sc_service::TFullClient< - Block, - RuntimeApi, - sc_executor::WasmExecutor, ->; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; type FullGrandpaBlockImport = @@ -34,6 +47,79 @@ type FullBeefyBlockImport = /// imported and generated. const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512; +pub fn frontier_database_dir(config: &Configuration, path: &str) -> std::path::PathBuf { + config + .base_path + .config_dir(config.chain_spec.id()) + .join("frontier") + .join(path) +} +pub fn open_frontier_backend( + client: Arc, + config: &Configuration, + eth_config: &mut EthConfiguration, +) -> Result, String> +where + C: ProvideRuntimeApi + StorageProvider + AuxStore, + C: HeaderBackend + HeaderMetadata, + C: Send + Sync + 'static, + C::Api: fp_rpc::EthereumRuntimeRPCApi, + BE: Backend + 'static, + BE::State: StateBackend, +{ + let frontier_backend = match eth_config.frontier_backend_type { + BackendType::KeyValue => { + fc_db::Backend::KeyValue(Arc::new(fc_db::kv::Backend::::new( + client, + &fc_db::kv::DatabaseSettings { + source: match config.database { + DatabaseSource::RocksDb { .. } => DatabaseSource::RocksDb { + path: frontier_database_dir(config, "db"), + cache_size: 0, + }, + DatabaseSource::ParityDb { .. } => DatabaseSource::ParityDb { + path: frontier_database_dir(config, "paritydb"), + }, + DatabaseSource::Auto { .. } => DatabaseSource::Auto { + rocksdb_path: frontier_database_dir(config, "db"), + paritydb_path: frontier_database_dir(config, "paritydb"), + cache_size: 0, + }, + _ => { + return Err( + "Supported db sources: `rocksdb` | `paritydb` | `auto`".to_string() + ) + } + }, + }, + )?)) + } + BackendType::Sql => { + let overrides = Arc::new(StorageOverrideHandler::new(client.clone())); + let sqlite_db_path = frontier_database_dir(config, "sql"); + std::fs::create_dir_all(&sqlite_db_path).expect("failed creating sql db directory"); + let backend = futures::executor::block_on(fc_db::sql::Backend::new( + fc_db::sql::BackendConfig::Sqlite(fc_db::sql::SqliteBackendConfig { + path: Path::new("sqlite:///") + .join(sqlite_db_path) + .join("frontier.db3") + .to_str() + .expect("frontier sql path error"), + create_if_missing: true, + thread_count: eth_config.frontier_sql_backend_thread_count, + cache_size: eth_config.frontier_sql_backend_cache_size, + }), + eth_config.frontier_sql_backend_pool_size, + std::num::NonZeroU32::new(eth_config.frontier_sql_backend_num_ops_timeout), + overrides.clone(), + )) + .unwrap_or_else(|err| panic!("failed creating sql backend: {:?}", err)); + fc_db::Backend::Sql(Arc::new(backend)) + } + }; + + Ok(frontier_backend) +} pub type Service = sc_service::PartialComponents< FullClient, FullBackend, @@ -44,17 +130,25 @@ pub type Service = sc_service::PartialComponents< sc_consensus_babe::BabeBlockImport< Block, FullClient, - FullBeefyBlockImport, + FullBeefyBlockImport< + FrontierBlockImport, + ecdsa_crypto::AuthorityId, + >, >, sc_consensus_grandpa::LinkHalf, sc_consensus_babe::BabeLink, sc_consensus_beefy::BeefyVoterLinks, sc_consensus_beefy::BeefyRPCLinks, + Arc>, + Arc>, Option, ), >; -pub fn new_partial(config: &Configuration) -> Result { +pub fn new_partial( + config: &Configuration, + eth_config: &mut EthConfiguration, +) -> Result { let telemetry = config .telemetry_endpoints .clone() @@ -66,13 +160,30 @@ pub fn new_partial(config: &Configuration) -> Result { }) .transpose()?; - let executor = sc_service::new_wasm_executor::(&config.executor); + let heap_pages = config + .executor + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { + extra_pages: h as _, + }); + + let wasm_builder = WasmExecutor::builder() + .with_execution_method(config.executor.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_ignore_onchain_heap_pages(true) + .with_max_runtime_instances(config.executor.max_runtime_instances) + .with_runtime_cache_size(config.executor.runtime_cache_size); + + let executor = wasm_builder.build(); + let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts::( + sc_service::new_full_parts::( config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, )?; + let client = Arc::new(client); let telemetry = telemetry.map(|(worker, telemetry)| { @@ -100,9 +211,12 @@ pub fn new_partial(config: &Configuration) -> Result { telemetry.as_ref().map(|x| x.handle()), )?; + let frontier_block_import = + FrontierBlockImport::new(grandpa_block_import.clone(), client.clone()); + let (beefy_block_import, beefy_voter_links, beefy_rpc_links) = sc_consensus_beefy::beefy_block_import_and_links( - grandpa_block_import.clone(), + frontier_block_import, backend.clone(), client.clone(), config.prometheus_registry().cloned(), @@ -113,8 +227,12 @@ pub fn new_partial(config: &Configuration) -> Result { beefy_block_import, client.clone(), )?; + let slot_duration = babe_link.config().slot_duration(); + let storage_override = Arc::new(StorageOverrideHandler::::new(client.clone())); + let frontier_backend = Arc::new(open_frontier_backend(client.clone(), config, eth_config)?); + let (import_queue, babe_worker_handle) = sc_consensus_babe::import_queue(ImportQueueParams { link: babe_link.clone(), block_import: block_import.clone(), @@ -155,16 +273,19 @@ pub fn new_partial(config: &Configuration) -> Result { babe_link, beefy_voter_links, beefy_rpc_links, + frontier_backend, + storage_override, telemetry, ), }) } -/// Builds a new service for a full client. -pub fn new_full< +// Builds a new service for a full client. +pub async fn new_full< N: sc_network::NetworkBackend::Hash>, >( config: Configuration, + mut eth_config: EthConfiguration, ) -> Result { let sc_service::PartialComponents { client, @@ -175,14 +296,30 @@ pub fn new_full< select_chain, transaction_pool, other: - (block_import, grandpa_link, babe_link, beefy_voter_links, beefy_rpc_links, mut telemetry), - } = new_partial(&config)?; + ( + block_import, + grandpa_link, + babe_link, + beefy_voter_links, + beefy_rpc_links, + frontier_backend, + storage_override, + mut telemetry, + ), + } = new_partial(&config, &mut eth_config)?; + + let FrontierPartialComponents { + filter_pool, + fee_history_cache, + fee_history_cache_limit, + } = new_frontier_partial(ð_config)?; let mut net_config = sc_network::config::FullNetworkConfiguration::< Block, ::Hash, N, >::new(&config.network, config.prometheus_registry().cloned()); + let metrics = N::register_notification_metrics(config.prometheus_registry()); let peer_store_handle = net_config.peer_store_handle(); @@ -311,6 +448,33 @@ pub fn new_full< telemetry: telemetry.as_mut(), })?; + // Sinks for pubsub notifications. + // Everytime a new subscription is created, a new mpsc channel is added to the sink pool. + // The MappingSyncWorker sends through the channel on block import and the subscription emits a notification to the subscriber on receiving a message through this channel. + // This way we avoid race conditions when using native substrate block import notification stream. + let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks< + fc_mapping_sync::EthereumBlockNotification, + > = Default::default(); + let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks); + + spawn_frontier_tasks( + &task_manager, + FrontierTasksParams { + client: client.clone(), + backend: backend.clone(), + frontier_backend, + frontier_partial_components: FrontierPartialComponents { + filter_pool, + fee_history_cache, + fee_history_cache_limit, + }, + storage_override, + sync: sync_service.clone(), + pubsub_notification_sinks, + }, + ) + .await; + if role.is_authority() { let proposer_factory = sc_basic_authorship::ProposerFactory::new( task_manager.spawn_handle(), diff --git a/operator/pallets/validator-set/src/lib.rs b/operator/pallets/validator-set/src/lib.rs index 09213120..09f067ba 100644 --- a/operator/pallets/validator-set/src/lib.rs +++ b/operator/pallets/validator-set/src/lib.rs @@ -35,6 +35,8 @@ //! and [`pallet_session::Config::ValidatorIdOf`] must be [`ConvertInto`]. #![cfg_attr(not(feature = "std"), no_std)] +// We need this because it clashes with Polkadot macro pallet::pallet +#![allow(clippy::manual_inspect)] mod benchmarking; mod mock; diff --git a/operator/runtime/Cargo.toml b/operator/runtime/Cargo.toml index 2c8243e5..1fba10bb 100644 --- a/operator/runtime/Cargo.toml +++ b/operator/runtime/Cargo.toml @@ -15,7 +15,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } datahaven-runtime-common.workspace = true -fp-account = { workspace = true, features = [ "serde" ]} +fp-account = { workspace = true, features = ["serde"] } +fp-evm = { workspace = true, features = ["serde"] } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde", "try-runtime"] } frame-benchmarking = { optional = true, workspace = true } frame-executive.workspace = true frame-metadata-hash-extension.workspace = true @@ -31,9 +34,6 @@ pallet-babe.workspace = true pallet-balances.workspace = true pallet-beefy-mmr.workspace = true pallet-beefy.workspace = true -pallet-ethereum.workspace = true -pallet-evm-chain-id.workspace = true -pallet-evm.workspace = true pallet-grandpa.workspace = true pallet-identity.workspace = true pallet-im-online.workspace = true @@ -69,6 +69,10 @@ sp-storage.workspace = true sp-transaction-pool.workspace = true sp-version = { features = ["serde"], workspace = true } +pallet-ethereum.workspace = true +pallet-evm-chain-id.workspace = true +pallet-evm.workspace = true + # Snowbridge snowbridge-beacon-primitives.workspace = true snowbridge-pallet-ethereum-client.workspace = true @@ -81,32 +85,28 @@ default = ["std"] std = [ "codec/std", "scale-info/std", - "frame-executive/std", "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", - "frame-benchmarking?/std", "frame-try-runtime?/std", - "datahaven-runtime-common/std", - "pallet-authorship/std", - "pallet-babe/std", - "pallet-beefy/std", - "pallet-beefy-mmr/std", - "pallet-balances/std", + "pallet-babe/std", + "pallet-beefy/std", + "pallet-beefy-mmr/std", + "pallet-balances/std", "pallet-im-online/std", - "pallet-grandpa/std", + "pallet-grandpa/std", "pallet-identity/std", "pallet-multisig/std", - "pallet-mmr/std", - "pallet-offences/std", - "pallet-preimage/std", - "pallet-scheduler/std", + "pallet-mmr/std", + "pallet-offences/std", + "pallet-preimage/std", + "pallet-scheduler/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -114,13 +114,10 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "pallet-validator-set/std", - "polkadot-primitives/std", - "polkadot-runtime-common/std", - + "polkadot-runtime-common/std", "snowbridge-beacon-primitives/std", "snowbridge-pallet-ethereum-client/std", - "sp-api/std", "sp-block-builder/std", "sp-consensus-babe/std", @@ -136,10 +133,7 @@ std = [ "sp-std/std", "sp-transaction-pool/std", "sp-version/std", - "substrate-wasm-builder", - - "pallet-mmr/std", "fp-account/std", "pallet-evm/std", "pallet-evm-chain-id/std", @@ -166,7 +160,7 @@ runtime-benchmarks = [ "pallet-beefy-mmr/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", "snowbridge-pallet-ethereum-client/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-evm/runtime-benchmarks", @@ -201,6 +195,7 @@ try-runtime = [ "sp-runtime/try-runtime", "pallet-evm/try-runtime", "pallet-ethereum/try-runtime", + "fp-self-contained/try-runtime" ] fast-runtime = [ diff --git a/operator/runtime/src/apis.rs b/operator/runtime/src/apis.rs index cc5ebfd1..aa876931 100644 --- a/operator/runtime/src/apis.rs +++ b/operator/runtime/src/apis.rs @@ -23,37 +23,48 @@ // // For more information, please refer to +// Local module imports +use super::{ + AccountId, Babe, Balance, Beefy, BeefyMmrLeaf, Block, BlockNumber, Ethereum, Executive, + Grandpa, Historical, InherentDataExt, Mmr, Nonce, Runtime, RuntimeCall, RuntimeGenesisConfig, + RuntimeOrigin, SessionKeys, System, TransactionPayment, UncheckedExtrinsic, VERSION, +}; // External crates imports use crate::configs::BABE_GENESIS_EPOCH_CONFIG; use alloc::{vec, vec::Vec}; use codec::Encode; use datahaven_runtime_common::time::EpochDurationInBlocks; +use fp_rpc::TransactionStatus; +use frame_support::traits::OnFinalize; +use pallet_ethereum::Transaction as EthereumTransaction; +use pallet_evm::GasWeightMapping; + +use frame_support::traits::KeyOwnerProofSystem; use frame_support::{ genesis_builder_helper::{build_state, get_preset}, weights::Weight, }; +use pallet_ethereum::Call::transact; +use pallet_evm::Account as EVMAccount; +use pallet_evm::FeeCalculator; +use pallet_evm::Runner; +use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; +use polkadot_primitives::Hash; use sp_api::impl_runtime_apis; use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, AncestryHelper, }; -use sp_core::OpaqueMetadata; +use sp_core::{Get, H256, U256}; +use sp_core::{OpaqueMetadata, H160}; +use sp_runtime::traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf}; +use sp_runtime::transaction_validity::TransactionValidityError; use sp_runtime::{ traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, + ApplyExtrinsicResult, Permill, }; use sp_version::RuntimeVersion; -// Local module imports -use super::{ - AccountId, Babe, Balance, Beefy, BeefyMmrLeaf, Block, BlockNumber, Executive, Grandpa, - Historical, InherentDataExt, Mmr, Nonce, Runtime, RuntimeCall, RuntimeGenesisConfig, - SessionKeys, System, TransactionPayment, VERSION, -}; -use frame_support::traits::KeyOwnerProofSystem; -use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; -use polkadot_primitives::Hash; - /// MMR helper types. mod mmr { use super::Runtime; @@ -64,6 +75,77 @@ mod mmr { pub type Hash = ::Output; } +#[derive(Clone)] +pub struct TransactionConverter; + +impl fp_self_contained::SelfContainedCall for RuntimeCall { + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + fn check_self_contained(&self) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + signed_info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => { + call.validate_self_contained(signed_info, dispatch_info, len) + } + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => { + call.pre_dispatch_self_contained(info, dispatch_info, len) + } + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { + Some(call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info), + ))) + } + _ => None, + } + } +} + +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_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { @@ -425,6 +507,7 @@ impl_runtime_apis! { (list, storage_info) } + #[expect(non_local_definitions)] fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { @@ -483,4 +566,222 @@ impl_runtime_apis! { vec![] } } + + impl fp_rpc::EthereumRuntimeRPCApi for Runtime { + fn chain_id() -> u64 { + ::ChainId::get() + } + + fn account_basic(address: H160) -> EVMAccount { + let (account, _) = pallet_evm::Pallet::::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(address) + } + + fn author() -> H160 { + >::find_author() + } + + fn storage_at(address: H160, index: U256) -> H256 { + let mut tmp = [0u8; 32]; + index.to_big_endian(&mut tmp); + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) + } + + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + gas_limit.low_u64() + }; + + let (weight_limit, proof_size_base_cost) = (None, None); + + #[allow(clippy::or_fun_call)] + ::Runner::create( + from, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option>, + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn extrinsic_filter( + xts: Vec<::Extrinsic>, + ) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None + }).collect::>() + } + + fn elasticity() -> Option { + None + } + + fn gas_limit_multiplier_support() {} + + fn pending_block( + xts: Vec<::Extrinsic>, + ) -> (Option, Option>) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } + + Ethereum::on_finalize(System::block_number() + 1); + + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn initialize_pending_block(header: &::Header) { + Executive::initialize_block(header); + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } } diff --git a/operator/runtime/src/lib.rs b/operator/runtime/src/lib.rs index 4c2ebc87..baa241d2 100644 --- a/operator/runtime/src/lib.rs +++ b/operator/runtime/src/lib.rs @@ -2,6 +2,7 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] +extern crate alloc; #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -10,7 +11,6 @@ pub mod apis; mod benchmarks; pub mod configs; -extern crate alloc; use alloc::vec::Vec; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, @@ -24,6 +24,7 @@ use fp_account::EthereumSignature; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; +use sp_core::H160; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know @@ -174,7 +175,10 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + fp_self_contained::UncheckedExtrinsic; + +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload;