feat(operator): 🏗️ add frontier client (#13)

- [x] Add frontier client dependencies
- [x] Add ethereum client config
- [x] Add changes to cli.rs
- [x] Add changes to service.rs
- [x] Add runtime apis
- [x] Add changes to chain spec
- [ ] Add tests

---------

Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
This commit is contained in:
Gonza Montiel 2025-04-14 13:40:24 +02:00 committed by GitHub
parent 7e0f043d7f
commit 535c38de6a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1389 additions and 81 deletions

462
operator/Cargo.lock generated
View file

@ -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"

View file

@ -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 }

View file

@ -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",
]

View file

@ -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<Subcommand>,
#[clap(flatten)]
#[allow(missing_docs)]
#[command(flatten)]
pub run: RunCmd,
/// Choose sealing method.
#[arg(long, value_enum, ignore_case = true)]
pub sealing: Option<Sealing>,
#[command(flatten)]
pub eth: EthConfiguration,
}
#[derive(Debug, clap::Subcommand)]

View file

@ -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<B> = sc_service::TFullBackend<B>;
/// Full client.
pub type FullClient<B, RA, HF> = sc_service::TFullClient<B, RA, WasmExecutor<HF>>;
/// A set of APIs that every runtime must implement.
pub trait _BaseRuntimeApiCollection<Block: BlockT>:
sp_api::ApiExt<Block>
+ sp_api::Metadata<Block>
+ sp_block_builder::BlockBuilder<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
{
}
impl<Block, Api> _BaseRuntimeApiCollection<Block> for Api
where
Block: BlockT,
Api: sp_api::ApiExt<Block>
+ sp_api::Metadata<Block>
+ sp_block_builder::BlockBuilder<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
{
}
/// A set of APIs that template runtime must implement.
pub trait _RuntimeApiCollection<Block: BlockT, Balance: Codec + MaybeDisplay>:
_BaseRuntimeApiCollection<Block>
+ EthCompatRuntimeApiCollection<Block>
+ sp_consensus_babe::BabeApi<Block>
+ sp_consensus_grandpa::GrandpaApi<Block>
+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>
{
}
impl<Block, Balance, Api> _RuntimeApiCollection<Block, Balance> for Api
where
Block: BlockT,
Balance: Codec + MaybeDisplay,
Api: _BaseRuntimeApiCollection<Block>
+ EthCompatRuntimeApiCollection<Block>
+ sp_consensus_babe::BabeApi<Block>
+ sp_consensus_grandpa::GrandpaApi<Block>
+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>,
{
}

View file

@ -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<service::FullClient>, 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,
<datahaven_runtime::opaque::Block as sp_runtime::traits::Block>::Hash,
>,
>(config)
>(
config, cli.eth
)
.await
.map_err(sc_cli::Error::Service),
sc_network::config::NetworkBackendType::Litep2p => {
service::new_full::<sc_network::Litep2pNetworkBackend>(config)
service::new_full::<sc_network::Litep2pNetworkBackend>(config, cli.eth)
.await
.map_err(sc_cli::Error::Service)
}
}

232
operator/node/src/eth.rs Normal file
View file

@ -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<B, C> = fc_db::Backend<B, C>;
/// 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<FilterPool>,
pub fee_history_cache: FeeHistoryCache,
pub fee_history_cache_limit: FeeHistoryCacheLimit,
}
pub fn new_frontier_partial(
config: &EthConfiguration,
) -> Result<FrontierPartialComponents, ServiceError> {
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<Block: BlockT>:
sp_api::ApiExt<Block> + fp_rpc::ConvertTransactionRuntimeApi<Block> + EthereumRuntimeRPCApi<Block>
{
}
impl<Block, Api> EthCompatRuntimeApiCollection<Block> for Api
where
Block: BlockT,
Api: sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ EthereumRuntimeRPCApi<Block>,
{
}
pub struct FrontierTasksParams<B, RA, HF>
where
B: BlockT<Hash = H256>,
RA: ConstructRuntimeApi<B, FullClient<B, RA, HF>>,
RA: Send + Sync + 'static,
RA::RuntimeApi: EthCompatRuntimeApiCollection<B>,
HF: HostFunctions + 'static,
{
pub client: Arc<FullClient<B, RA, HF>>,
pub backend: Arc<FullBackend<B>>,
pub frontier_backend: Arc<FrontierBackend<B, FullClient<B, RA, HF>>>,
pub frontier_partial_components: FrontierPartialComponents,
pub storage_override: Arc<dyn StorageOverride<B>>,
pub sync: Arc<SyncingService<B>>,
pub pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<B>,
>,
>,
}
pub async fn spawn_frontier_tasks<B, RA, HF>(
task_manager: &TaskManager,
params: FrontierTasksParams<B, RA, HF>,
) where
B: BlockT<Hash = H256>,
RA: ConstructRuntimeApi<B, FullClient<B, RA, HF>>,
RA: Send + Sync + 'static,
RA::RuntimeApi: EthCompatRuntimeApiCollection<B>,
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,
),
);
}

View file

@ -4,7 +4,9 @@
mod benchmarking;
mod chain_spec;
mod cli;
mod client;
mod command;
mod eth;
mod rpc;
mod service;

View file

@ -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<Block, RuntimeApi, WasmExecutor<HostFunctions>>;
pub(crate) type FullClient = sc_service::TFullClient<
Block,
RuntimeApi,
sc_executor::WasmExecutor<sp_io::SubstrateHostFunctions>,
>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
type FullGrandpaBlockImport =
@ -34,6 +47,79 @@ type FullBeefyBlockImport<InnerBlockImport, AuthorityId> =
/// 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<C, BE>(
client: Arc<C>,
config: &Configuration,
eth_config: &mut EthConfiguration,
) -> Result<fc_db::Backend<Block, C>, String>
where
C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError>,
C: Send + Sync + 'static,
C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
BE: Backend<Block> + 'static,
BE::State: StateBackend<BlakeTwo256>,
{
let frontier_backend = match eth_config.frontier_backend_type {
BackendType::KeyValue => {
fc_db::Backend::KeyValue(Arc::new(fc_db::kv::Backend::<Block, C>::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<FullGrandpaBlockImport, ecdsa_crypto::AuthorityId>,
FullBeefyBlockImport<
FrontierBlockImport<Block, FullGrandpaBlockImport, FullClient>,
ecdsa_crypto::AuthorityId,
>,
>,
sc_consensus_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
sc_consensus_babe::BabeLink<Block>,
sc_consensus_beefy::BeefyVoterLinks<Block, ecdsa_crypto::AuthorityId>,
sc_consensus_beefy::BeefyRPCLinks<Block, ecdsa_crypto::AuthorityId>,
Arc<fc_db::Backend<Block, FullClient>>,
Arc<dyn StorageOverride<Block>>,
Option<Telemetry>,
),
>;
pub fn new_partial(config: &Configuration) -> Result<Service, ServiceError> {
pub fn new_partial(
config: &Configuration,
eth_config: &mut EthConfiguration,
) -> Result<Service, ServiceError> {
let telemetry = config
.telemetry_endpoints
.clone()
@ -66,13 +160,30 @@ pub fn new_partial(config: &Configuration) -> Result<Service, ServiceError> {
})
.transpose()?;
let executor = sc_service::new_wasm_executor::<sp_io::SubstrateHostFunctions>(&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::<Block, RuntimeApi, _>(
sc_service::new_full_parts::<Block, datahaven_runtime::apis::RuntimeApi, _>(
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<Service, ServiceError> {
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<Service, ServiceError> {
beefy_block_import,
client.clone(),
)?;
let slot_duration = babe_link.config().slot_duration();
let storage_override = Arc::new(StorageOverrideHandler::<Block, _, _>::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<Service, ServiceError> {
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<Block, <Block as sp_runtime::traits::Block>::Hash>,
>(
config: Configuration,
mut eth_config: EthConfiguration,
) -> Result<TaskManager, ServiceError> {
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(&eth_config)?;
let mut net_config = sc_network::config::FullNetworkConfiguration::<
Block,
<Block as sp_runtime::traits::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<Block>,
> = 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(),

View file

@ -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;

View file

@ -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 = [

View file

@ -23,37 +23,48 @@
//
// For more information, please refer to <http://unlicense.org>
// 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 = <Hashing as sp_runtime::traits::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<Result<Self::SignedInfo, TransactionValidityError>> {
match self {
RuntimeCall::Ethereum(call) => call.check_self_contained(),
_ => None,
}
}
fn validate_self_contained(
&self,
signed_info: &Self::SignedInfo,
dispatch_info: &DispatchInfoOf<RuntimeCall>,
len: usize,
) -> Option<TransactionValidity> {
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<RuntimeCall>,
len: usize,
) -> Option<Result<(), TransactionValidityError>> {
match self {
RuntimeCall::Ethereum(call) => {
call.pre_dispatch_self_contained(info, dispatch_info, len)
}
_ => None,
}
}
fn apply_self_contained(
self,
info: Self::SignedInfo,
) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
match self {
call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => {
Some(call.dispatch(RuntimeOrigin::from(
pallet_ethereum::RawOrigin::EthereumTransaction(info),
)))
}
_ => None,
}
}
}
impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
UncheckedExtrinsic::new_unsigned(
pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
)
}
}
impl_runtime_apis! {
impl sp_api::Core<Block> 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<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
@ -483,4 +566,222 @@ impl_runtime_apis! {
vec![]
}
}
impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
fn chain_id() -> u64 {
<Runtime as pallet_evm::Config>::ChainId::get()
}
fn account_basic(address: H160) -> EVMAccount {
let (account, _) = pallet_evm::Pallet::<Runtime>::account_basic(&address);
account
}
fn gas_price() -> U256 {
let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
gas_price
}
fn account_code_at(address: H160) -> Vec<u8> {
pallet_evm::AccountCodes::<Runtime>::get(address)
}
fn author() -> H160 {
<pallet_evm::Pallet<Runtime>>::find_author()
}
fn storage_at(address: H160, index: U256) -> H256 {
let mut tmp = [0u8; 32];
index.to_big_endian(&mut tmp);
pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
}
fn call(
from: H160,
to: H160,
data: Vec<u8>,
value: U256,
gas_limit: U256,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
nonce: Option<U256>,
estimate: bool,
access_list: Option<Vec<(H160, Vec<H256>)>>,
) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
let config = if estimate {
let mut config = <Runtime as pallet_evm::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 <Runtime as pallet_evm::Config>::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),
};
<Runtime as pallet_evm::Config>::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(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
fn create(
from: H160,
data: Vec<u8>,
value: U256,
gas_limit: U256,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
nonce: Option<U256>,
estimate: bool,
access_list: Option<Vec<(H160, Vec<H256>)>>,
) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
let config = if estimate {
let mut config = <Runtime as pallet_evm::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)]
<Runtime as pallet_evm::Config>::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(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
}
fn current_block() -> Option<pallet_ethereum::Block> {
pallet_ethereum::CurrentBlock::<Runtime>::get()
}
fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
pallet_ethereum::CurrentReceipts::<Runtime>::get()
}
fn current_all() -> (
Option<pallet_ethereum::Block>,
Option<Vec<pallet_ethereum::Receipt>>,
Option<Vec<TransactionStatus>>,
) {
(
pallet_ethereum::CurrentBlock::<Runtime>::get(),
pallet_ethereum::CurrentReceipts::<Runtime>::get(),
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
)
}
fn extrinsic_filter(
xts: Vec<<Block as BlockT>::Extrinsic>,
) -> Vec<EthereumTransaction> {
xts.into_iter().filter_map(|xt| match xt.0.function {
RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
_ => None
}).collect::<Vec<EthereumTransaction>>()
}
fn elasticity() -> Option<Permill> {
None
}
fn gas_limit_multiplier_support() {}
fn pending_block(
xts: Vec<<Block as BlockT>::Extrinsic>,
) -> (Option<pallet_ethereum::Block>, Option<Vec<TransactionStatus>>) {
for ext in xts.into_iter() {
let _ = Executive::apply_extrinsic(ext);
}
Ethereum::on_finalize(System::block_number() + 1);
(
pallet_ethereum::CurrentBlock::<Runtime>::get(),
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
)
}
fn initialize_pending_block(header: &<Block as BlockT>::Header) {
Executive::initialize_block(header);
}
}
impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
fn convert_transaction(transaction: EthereumTransaction) -> <Block as BlockT>::Extrinsic {
UncheckedExtrinsic::new_unsigned(
pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
)
}
}
}

View file

@ -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<Address, RuntimeCall, Signature, SignedExtra>;
fp_self_contained::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
pub type CheckedExtrinsic =
fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra, H160>;
/// The payload being signed in transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;