diff --git a/Cargo.lock b/Cargo.lock index 3b84060e49..741b737f21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -970,15 +970,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ "iana-time-zone", "js-sys", "num-integer", "num-traits", - "time 0.1.45", + "time 0.1.44", "wasm-bindgen", "winapi", ] @@ -1499,7 +1499,7 @@ dependencies = [ [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "clap", "parity-scale-codec", @@ -1514,7 +1514,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -1537,7 +1537,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-client-pov-recovery", @@ -1561,7 +1561,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-relay-chain" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1584,7 +1584,7 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -1607,7 +1607,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1631,7 +1631,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-client-cli", "cumulus-client-collator", @@ -1666,7 +1666,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1683,7 +1683,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "bytes", "cumulus-pallet-parachain-system-proc-macro", @@ -1712,7 +1712,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1723,7 +1723,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1739,7 +1739,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1759,7 +1759,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", @@ -1775,7 +1775,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1798,7 +1798,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "futures 0.3.28", @@ -1811,7 +1811,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1829,7 +1829,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1854,7 +1854,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1872,7 +1872,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-minimal-node" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "array-bytes 6.0.0", "async-trait", @@ -1906,7 +1906,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1936,7 +1936,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -2436,22 +2436,22 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.7" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.7" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 1.0.109", ] [[package]] @@ -2574,8 +2574,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm" version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1099df1dac16f32a136452ad98ee0f1ff42acd3e12ce65bea4462b61d656608a" +source = "git+https://github.com/purestake/evm?branch=tgm-record-external-cost#c3db4777854b8b5a7cc6f54b78de988c0c387b4f" dependencies = [ "auto_impl", "environmental", @@ -2595,8 +2594,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1f13264b044cb66f0602180f0bc781c29accb41ff560669a3ec15858d5b606" +source = "git+https://github.com/purestake/evm?branch=tgm-record-external-cost#c3db4777854b8b5a7cc6f54b78de988c0c387b4f" dependencies = [ "parity-scale-codec", "primitive-types", @@ -2607,8 +2605,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d43eadc395bd1a52990787ca1495c26b0248165444912be075c28909a853b8c" +source = "git+https://github.com/purestake/evm?branch=tgm-record-external-cost#c3db4777854b8b5a7cc6f54b78de988c0c387b4f" dependencies = [ "environmental", "evm-core", @@ -2619,8 +2616,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aa5b32f59ec582a5651978004e5c784920291263b7dcb6de418047438e37f4f" +source = "git+https://github.com/purestake/evm?branch=tgm-record-external-cost#c3db4777854b8b5a7cc6f54b78de988c0c387b4f" dependencies = [ "auto_impl", "environmental", @@ -2745,7 +2741,7 @@ dependencies = [ [[package]] name = "fc-consensus" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "async-trait", "fc-db", @@ -2762,7 +2758,7 @@ dependencies = [ [[package]] name = "fc-db" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-storage", "kvdb-rocksdb", @@ -2781,7 +2777,7 @@ dependencies = [ [[package]] name = "fc-mapping-sync" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fc-db", "fc-storage", @@ -2790,21 +2786,25 @@ dependencies = [ "futures 0.3.28", "futures-timer", "log", + "parking_lot 0.12.1", "sc-client-api", + "sc-utils", "sp-api", "sp-blockchain", + "sp-consensus", "sp-runtime", ] [[package]] name = "fc-rpc" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "ethereum-types", "evm", "fc-db", + "fc-mapping-sync", "fc-rpc-core", "fc-storage", "fp-ethereum", @@ -2830,6 +2830,7 @@ dependencies = [ "sc-service", "sc-transaction-pool", "sc-transaction-pool-api", + "sc-utils", "sp-api", "sp-block-builder", "sp-blockchain", @@ -2846,7 +2847,7 @@ dependencies = [ [[package]] name = "fc-rpc-core" version = "1.1.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "ethereum-types", @@ -2859,7 +2860,7 @@ dependencies = [ [[package]] name = "fc-storage" version = "1.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "ethereum-types", @@ -2911,7 +2912,7 @@ checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "windows-sys 0.42.0", ] @@ -3008,7 +3009,7 @@ dependencies = [ [[package]] name = "fp-account" version = "1.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "hex", "impl-serde 0.4.0", @@ -3026,7 +3027,7 @@ dependencies = [ [[package]] name = "fp-consensus" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "parity-scale-codec", @@ -3038,7 +3039,7 @@ dependencies = [ [[package]] name = "fp-ethereum" version = "1.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "ethereum-types", @@ -3052,7 +3053,7 @@ dependencies = [ [[package]] name = "fp-evm" version = "3.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "evm", "frame-support", @@ -3066,7 +3067,7 @@ dependencies = [ [[package]] name = "fp-rpc" version = "3.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "ethereum", "ethereum-types", @@ -3083,7 +3084,7 @@ dependencies = [ [[package]] name = "fp-self-contained" version = "1.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "frame-support", "parity-scale-codec", @@ -3095,7 +3096,7 @@ dependencies = [ [[package]] name = "fp-storage" version = "2.0.0" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "parity-scale-codec", "serde", @@ -7118,7 +7119,7 @@ dependencies = [ [[package]] name = "pallet-base-fee" version = "1.0.0" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "frame-support", @@ -7360,7 +7361,7 @@ dependencies = [ [[package]] name = "pallet-ethereum" version = "4.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "environmental", "ethereum", @@ -7374,7 +7375,6 @@ dependencies = [ "frame-support", "frame-system", "pallet-evm", - "pallet-timestamp", "parity-scale-codec", "scale-info", "sp-io", @@ -7428,7 +7428,7 @@ dependencies = [ [[package]] name = "pallet-evm" version = "6.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "environmental", "evm", @@ -7438,12 +7438,13 @@ dependencies = [ "frame-support", "frame-system", "hex", + "hex-literal", "impl-trait-for-tuples", "log", - "pallet-timestamp", "parity-scale-codec", "rlp", "scale-info", + "sha3", "sp-core", "sp-io", "sp-runtime", @@ -7536,7 +7537,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-blake2" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", ] @@ -7544,7 +7545,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-bn128" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "sp-core", @@ -7700,7 +7701,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-dispatch" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "frame-support", @@ -7747,7 +7748,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "num", @@ -7950,7 +7951,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "tiny-keccak", @@ -7959,7 +7960,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-simple" version = "2.0.0-dev" -source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#ba18cb2fa6aa0e99f7bd690ab1edc1df173350a1" +source = "git+https://github.com/purestake/frontier?branch=moonbeam-polkadot-v0.9.40#6df962a4eac00a00dd55cf7506a64d0ec698687d" dependencies = [ "fp-evm", "ripemd", @@ -8925,7 +8926,7 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#efefd824aa96cac25376085979ab2a9526c052f5" +source = "git+https://github.com/purestake/cumulus?branch=moonbeam-polkadot-v0.9.40#0d8911b7557bad5788909fc71cadb916b041417b" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -9029,7 +9030,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", "winapi", ] @@ -9042,7 +9043,7 @@ checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", "windows-sys 0.42.0", ] @@ -10913,15 +10914,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.4.3" @@ -10929,7 +10921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.8", - "redox_syscall 0.2.16", + "redox_syscall", "thiserror", ] @@ -11016,6 +11008,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -14245,15 +14246,16 @@ checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.37.6", - "windows-sys 0.45.0", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] @@ -14362,9 +14364,9 @@ dependencies = [ [[package]] name = "time" -version = "0.1.45" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -16325,23 +16327,3 @@ dependencies = [ "cc", "libc", ] - -[[patch.unused]] -name = "evm" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" - -[[patch.unused]] -name = "evm-core" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" - -[[patch.unused]] -name = "evm-gasometer" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" - -[[patch.unused]] -name = "evm-runtime" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" diff --git a/Cargo.toml b/Cargo.toml index 9833d127aa..d01303629c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -226,11 +226,9 @@ ethereum = { version = "0.14.0", default-features = false, features = [ "with-codec", ] } ethereum-types = { version = "0.14", default-features = false } -evm = { version = "0.39.0", default-features = false, features = [ - "with-codec", -] } -evm-gasometer = { version = "0.39.0", default-features = false } -evm-runtime = { version = "0.39.0", default-features = false } +evm = { git = "https://github.com/purestake/evm", branch = "tgm-record-external-cost", default-features = false } +evm-gasometer = { git = "https://github.com/purestake/evm", branch = "tgm-record-external-cost", default-features = false } +evm-runtime = { git = "https://github.com/purestake/evm", branch = "tgm-record-external-cost", default-features = false } fp-ethereum = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } fp-evm = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } fp-rpc = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } @@ -238,16 +236,28 @@ fp-self-contained = { git = "https://github.com/purestake/frontier", branch = "m pallet-base-fee = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } pallet-ethereum = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ "forbid-evm-reentrancy", + "evm-with-weight-limit", ] } pallet-evm = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ "forbid-evm-reentrancy", + "evm-with-weight-limit", +] } +pallet-evm-precompile-blake2 = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ + "evm-with-weight-limit", +] } +pallet-evm-precompile-bn128 = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ + "evm-with-weight-limit", +] } +pallet-evm-precompile-dispatch = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ + "evm-with-weight-limit", +] } +pallet-evm-precompile-modexp = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ + "evm-with-weight-limit", ] } -pallet-evm-precompile-blake2 = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } -pallet-evm-precompile-bn128 = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } -pallet-evm-precompile-dispatch = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } -pallet-evm-precompile-modexp = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } pallet-evm-precompile-sha3fips = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } -pallet-evm-precompile-simple = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40", default-features = false, features = [ + "evm-with-weight-limit", +] } # Frontier (client) fc-consensus = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.40" } @@ -364,12 +374,6 @@ tracing-core = "0.1.29" trie-root = "0.15.2" url = "2.2.2" -[patch.crates-io] -evm = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355" } -evm-core = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355" } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355" } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355" } - # The list of dependencies below (which can be both direct and indirect dependencies) are crates # that are suspected to be CPU-intensive, and that are unlikely to require debugging (as some of # their debug info might be missing) or to require to be frequently recompiled. We compile these diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 5486750ca7..566d4eb6d7 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -614,16 +614,31 @@ where let overrides = crate::rpc::overrides_handle(client.clone()); let fee_history_limit = rpc_config.fee_history_limit; - rpc::spawn_essential_tasks(rpc::SpawnTasksParams { - task_manager: &task_manager, - client: client.clone(), - substrate_backend: backend.clone(), - frontier_backend: frontier_backend.clone(), - filter_pool: filter_pool.clone(), - overrides: overrides.clone(), - fee_history_limit, - fee_history_cache: fee_history_cache.clone(), - }); + // 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); + + rpc::spawn_essential_tasks( + rpc::SpawnTasksParams { + task_manager: &task_manager, + client: client.clone(), + substrate_backend: backend.clone(), + frontier_backend: frontier_backend.clone(), + filter_pool: filter_pool.clone(), + overrides: overrides.clone(), + fee_history_limit, + fee_history_cache: fee_history_cache.clone(), + }, + sync_service.clone(), + pubsub_notification_sinks.clone(), + ); let ethapi_cmd = rpc_config.ethapi.clone(); let tracing_requesters = @@ -669,6 +684,7 @@ where let overrides = overrides.clone(); let fee_history_cache = fee_history_cache.clone(); let block_data_cache = block_data_cache.clone(); + let pubsub_notification_sinks = pubsub_notification_sinks.clone(); move |deny_unsafe, subscription_task_executor| { let deps = rpc::FullDeps { @@ -690,6 +706,7 @@ where xcm_senders: None, block_data_cache: block_data_cache.clone(), overrides: overrides.clone(), + forced_parent_hashes: None, }; if ethapi_cmd.contains(&EthApiCmd::Debug) || ethapi_cmd.contains(&EthApiCmd::Trace) { rpc::create_full( @@ -699,10 +716,17 @@ where tracing_requesters: tracing_requesters.clone(), trace_filter_max_count: rpc_config.ethapi_trace_max_count, }), + pubsub_notification_sinks.clone(), ) .map_err(Into::into) } else { - rpc::create_full(deps, subscription_task_executor, None).map_err(Into::into) + rpc::create_full( + deps, + subscription_task_executor, + None, + pubsub_notification_sinks.clone(), + ) + .map_err(Into::into) } } }; @@ -1090,16 +1114,32 @@ where }), ); } - rpc::spawn_essential_tasks(rpc::SpawnTasksParams { - task_manager: &task_manager, - client: client.clone(), - substrate_backend: backend.clone(), - frontier_backend: frontier_backend.clone(), - filter_pool: filter_pool.clone(), - overrides: overrides.clone(), - fee_history_limit, - fee_history_cache: fee_history_cache.clone(), - }); + + // 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); + + rpc::spawn_essential_tasks( + rpc::SpawnTasksParams { + task_manager: &task_manager, + client: client.clone(), + substrate_backend: backend.clone(), + frontier_backend: frontier_backend.clone(), + filter_pool: filter_pool.clone(), + overrides: overrides.clone(), + fee_history_limit, + fee_history_cache: fee_history_cache.clone(), + }, + sync_service.clone(), + pubsub_notification_sinks.clone(), + ); let ethapi_cmd = rpc_config.ethapi.clone(); let tracing_requesters = if ethapi_cmd.contains(&EthApiCmd::Debug) || ethapi_cmd.contains(&EthApiCmd::Trace) { @@ -1142,6 +1182,7 @@ where let overrides = overrides.clone(); let fee_history_cache = fee_history_cache.clone(); let block_data_cache = block_data_cache.clone(); + let pubsub_notification_sinks = pubsub_notification_sinks.clone(); move |deny_unsafe, subscription_task_executor| { let deps = rpc::FullDeps { @@ -1163,6 +1204,7 @@ where xcm_senders: xcm_senders.clone(), overrides: overrides.clone(), block_data_cache: block_data_cache.clone(), + forced_parent_hashes: None, }; if ethapi_cmd.contains(&EthApiCmd::Debug) || ethapi_cmd.contains(&EthApiCmd::Trace) { @@ -1173,10 +1215,17 @@ where tracing_requesters: tracing_requesters.clone(), trace_filter_max_count: rpc_config.ethapi_trace_max_count, }), + pubsub_notification_sinks.clone(), ) .map_err(Into::into) } else { - rpc::create_full(deps, subscription_task_executor, None).map_err(Into::into) + rpc::create_full( + deps, + subscription_task_executor, + None, + pubsub_notification_sinks.clone(), + ) + .map_err(Into::into) } } }; diff --git a/node/service/src/rpc.rs b/node/service/src/rpc.rs index ba63e9b438..ae8daf075f 100644 --- a/node/service/src/rpc.rs +++ b/node/service/src/rpc.rs @@ -129,6 +129,8 @@ pub struct FullDeps { pub overrides: Arc>, /// Cache for Ethereum block data. pub block_data_cache: Arc>, + /// Mandated parent hashes for a given block hash. + pub forced_parent_hashes: Option>, } pub struct TracingConfig { @@ -169,6 +171,11 @@ pub fn create_full( deps: FullDeps, subscription_task_executor: SubscriptionTaskExecutor, maybe_tracing_config: Option, + pubsub_notification_sinks: Arc< + fc_mapping_sync::EthereumBlockNotificationSinks< + fc_mapping_sync::EthereumBlockNotification, + >, + >, ) -> Result, Box> where BE: Backend + 'static, @@ -215,6 +222,7 @@ where xcm_senders, overrides, block_data_cache, + forced_parent_hashes, } = deps; io.merge(System::new(Arc::clone(&client), Arc::clone(&pool), deny_unsafe).into_rpc())?; @@ -249,6 +257,7 @@ where fee_history_cache, fee_history_limit, 10, + forced_parent_hashes, ) .replace_config::>() .into_rpc(), @@ -286,6 +295,7 @@ where sync.clone(), subscription_task_executor, overrides, + pubsub_notification_sinks.clone(), ) .into_rpc(), )?; @@ -345,8 +355,15 @@ pub struct SpawnTasksParams<'a, B: BlockT, C, BE> { } /// Spawn the tasks that are required to run Moonbeam. -pub fn spawn_essential_tasks(params: SpawnTasksParams) -where +pub fn spawn_essential_tasks( + params: SpawnTasksParams, + sync: Arc>, + pubsub_notification_sinks: Arc< + fc_mapping_sync::EthereumBlockNotificationSinks< + fc_mapping_sync::EthereumBlockNotification, + >, + >, +) where C: ProvideRuntimeApi + BlockOf, C: HeaderBackend + HeaderMetadata + 'static, C: BlockchainEvents + StorageProvider, @@ -373,6 +390,8 @@ where 3, 0, SyncStrategy::Parachain, + sync, + pubsub_notification_sinks, ) .for_each(|()| futures::future::ready(())), ); diff --git a/pallets/erc20-xcm-bridge/src/lib.rs b/pallets/erc20-xcm-bridge/src/lib.rs index 9d1ec8546a..8a3a0e5c35 100644 --- a/pallets/erc20-xcm-bridge/src/lib.rs +++ b/pallets/erc20-xcm-bridge/src/lib.rs @@ -38,7 +38,7 @@ pub mod pallet { use ethereum_types::BigEndianHash; use fp_evm::{ExitReason, ExitSucceed}; use frame_support::pallet_prelude::*; - use pallet_evm::Runner; + use pallet_evm::{GasWeightMapping, Runner}; use sp_core::{H160, H256, U256}; use sp_std::vec::Vec; use xcm::latest::{ @@ -66,11 +66,7 @@ pub mod pallet { Erc20Matcher::::is_erc20_asset(asset) } pub fn weight_of_erc20_transfer() -> Weight { - let gas_limit = T::Erc20TransferGasLimit::get(); - Weight::from_parts( - T::Erc20TransferGasLimit::get().saturating_mul(T::WeightPerGas::get().ref_time()), - gas_limit / 4, // TODO: apply gas/proof_size ratio - ) + T::GasWeightMapping::gas_to_weight(T::Erc20TransferGasLimit::get(), true) } fn erc20_transfer( erc20_contract_address: H160, @@ -86,6 +82,9 @@ pub mod pallet { // append amount to be transferred input.extend_from_slice(H256::from_uint(&amount).as_bytes()); + let weight_limit = + T::GasWeightMapping::gas_to_weight(T::Erc20TransferGasLimit::get(), true); + let exec_info = T::EvmRunner::call( from, erc20_contract_address, @@ -98,6 +97,8 @@ pub mod pallet { Default::default(), false, false, + Some(weight_limit), + Some(0), &::config(), ) .map_err(|_| Erc20TransferError::EvmCallFail)?; diff --git a/pallets/ethereum-xcm/Cargo.toml b/pallets/ethereum-xcm/Cargo.toml index 6cba6c8f8f..3dae23aa60 100644 --- a/pallets/ethereum-xcm/Cargo.toml +++ b/pallets/ethereum-xcm/Cargo.toml @@ -4,7 +4,7 @@ authors = [ "Parity Technologies " ] description = "Xcm Transact compatibility for pallet-etherum." edition = "2021" license = "Apache-2.0" -repository = "https://github.com/paritytech/frontier/" +repository = "https://github.com/purestake/moonbeam/" version = "1.0.0-dev" [package.metadata.docs.rs] diff --git a/pallets/ethereum-xcm/src/lib.rs b/pallets/ethereum-xcm/src/lib.rs index 358e317a41..283f0efe46 100644 --- a/pallets/ethereum-xcm/src/lib.rs +++ b/pallets/ethereum-xcm/src/lib.rs @@ -232,6 +232,14 @@ pub mod pallet { } impl Pallet { + fn transaction_len(transaction: &Transaction) -> u64 { + transaction + .encode() + .len() + // pallet + call indexes + .saturating_add(2) as u64 + } + fn validate_and_apply( source: H160, xcm_transaction: EthereumXcmTransaction, @@ -249,6 +257,18 @@ impl Pallet { if let Some(transaction) = transaction { let transaction_data: TransactionData = (&transaction).into(); + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + transaction_data.gas_limit.unique_saturated_into(), + true, + ) { + weight_limit if weight_limit.proof_size() > 0 => ( + Some(weight_limit), + Some(Self::transaction_len(&transaction)), + ), + _ => (None, None), + }; + let _ = CheckEvmTransaction::::new( CheckEvmTransactionConfig { evm_config: T::config(), @@ -262,6 +282,8 @@ impl Pallet { is_transactional: true, }, transaction_data.into(), + weight_limit, + proof_size_base_cost, ) // We only validate the gas limit against the evm transaction cost. // No need to validate fee payment, as it is handled by the xcm executor. diff --git a/pallets/ethereum-xcm/src/mock.rs b/pallets/ethereum-xcm/src/mock.rs index ac9c528d8c..f66f1b7ff3 100644 --- a/pallets/ethereum-xcm/src/mock.rs +++ b/pallets/ethereum-xcm/src/mock.rs @@ -141,12 +141,18 @@ impl FindAuthor for FindAuthorTruncated { } } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { pub const TransactionByteFee: u64 = 1; pub const ChainId: u64 = 42; pub const EVMModuleId: PalletId = PalletId(*b"py/evmpa"); pub const BlockGasLimit: U256 = U256::MAX; pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } pub struct HashedAddressMapping; @@ -177,6 +183,9 @@ impl pallet_evm::Config for Test { type FindAuthor = FindAuthorTruncated; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -187,6 +196,7 @@ impl pallet_ethereum::Config for Test { type RuntimeEvent = RuntimeEvent; type StateRoot = IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } parameter_types! { diff --git a/pallets/ethereum-xcm/src/tests/v1/eip1559.rs b/pallets/ethereum-xcm/src/tests/v1/eip1559.rs index 362d36db73..6dd0103c7c 100644 --- a/pallets/ethereum-xcm/src/tests/v1/eip1559.rs +++ b/pallets/ethereum-xcm/src/tests/v1/eip1559.rs @@ -169,7 +169,7 @@ fn test_transact_xcm_evm_call_works() { ) .expect("Failed to call `bar`"); - let pending = Ethereum::pending(); + let pending = pallet_ethereum::Pending::::get(); assert!(pending.len() == 2); // Transaction is in Pending storage, with nonce 0 and status 1 (evm succeed). @@ -408,7 +408,7 @@ fn test_transaction_hash_collision() { ) .expect("Failed to execute transaction from Bob to Charlie"); - let mut hashes = Ethereum::pending() + let mut hashes = pallet_ethereum::Pending::::get() .iter() .map(|(tx, _, _)| tx.hash()) .collect::>(); diff --git a/pallets/ethereum-xcm/src/tests/v1/eip2930.rs b/pallets/ethereum-xcm/src/tests/v1/eip2930.rs index 414b249d44..d061b72a0c 100644 --- a/pallets/ethereum-xcm/src/tests/v1/eip2930.rs +++ b/pallets/ethereum-xcm/src/tests/v1/eip2930.rs @@ -181,7 +181,7 @@ fn test_transact_xcm_evm_call_works() { ) .expect("Failed to call `bar`"); - let pending = Ethereum::pending(); + let pending = pallet_ethereum::Pending::::get(); assert!(pending.len() == 2); // Transaction is in Pending storage, with nonce 0 and status 1 (evm succeed). @@ -422,7 +422,7 @@ fn test_transaction_hash_collision() { ) .expect("Failed to execute transaction from Bob to Charlie"); - let mut hashes = Ethereum::pending() + let mut hashes = pallet_ethereum::Pending::::get() .iter() .map(|(tx, _, _)| tx.hash()) .collect::>(); diff --git a/pallets/ethereum-xcm/src/tests/v1/legacy.rs b/pallets/ethereum-xcm/src/tests/v1/legacy.rs index 54e99195e1..55528fc16b 100644 --- a/pallets/ethereum-xcm/src/tests/v1/legacy.rs +++ b/pallets/ethereum-xcm/src/tests/v1/legacy.rs @@ -178,7 +178,7 @@ fn test_transact_xcm_evm_call_works() { ) .expect("Failed to call `bar`"); - let pending = Ethereum::pending(); + let pending = pallet_ethereum::Pending::::get(); assert!(pending.len() == 2); // Transaction is in Pending storage, with nonce 0 and status 1 (evm succeed). @@ -417,7 +417,7 @@ fn test_transaction_hash_collision() { ) .expect("Failed to execute transaction from Bob to Charlie"); - let mut hashes = Ethereum::pending() + let mut hashes = pallet_ethereum::Pending::::get() .iter() .map(|(tx, _, _)| tx.hash()) .collect::>(); diff --git a/pallets/ethereum-xcm/src/tests/v2.rs b/pallets/ethereum-xcm/src/tests/v2.rs index e4c7b3f614..43b48fcdcf 100644 --- a/pallets/ethereum-xcm/src/tests/v2.rs +++ b/pallets/ethereum-xcm/src/tests/v2.rs @@ -165,7 +165,7 @@ fn test_transact_xcm_evm_call_works() { ) .expect("Failed to call `bar`"); - let pending = Ethereum::pending(); + let pending = pallet_ethereum::Pending::::get(); assert!(pending.len() == 2); // Transaction is in Pending storage, with nonce 0 and status 1 (evm succeed). @@ -399,7 +399,7 @@ fn test_transaction_hash_collision() { ) .expect("Failed to execute transaction from Bob to Charlie"); - let mut hashes = Ethereum::pending() + let mut hashes = pallet_ethereum::Pending::::get() .iter() .map(|(tx, _, _)| tx.hash()) .collect::>(); diff --git a/pallets/randomness/src/lib.rs b/pallets/randomness/src/lib.rs index 67808a80b1..f449fe0a27 100644 --- a/pallets/randomness/src/lib.rs +++ b/pallets/randomness/src/lib.rs @@ -77,7 +77,7 @@ pub trait GetBabeData { #[pallet] pub mod pallet { use super::*; - use crate::weights::{SubstrateWeight, WeightInfo}; + use crate::weights::WeightInfo; use frame_support::traits::{Currency, ExistenceRequirement::KeepAlive}; use frame_support::{pallet_prelude::*, PalletId}; use frame_system::pallet_prelude::*; @@ -134,6 +134,8 @@ pub mod pallet { /// Babe requests expire and can be purged from storage after this many blocks/epochs #[pallet::constant] type EpochExpirationDelay: Get; + /// Weight info + type WeightInfo: WeightInfo; } #[pallet::error] @@ -236,7 +238,7 @@ pub mod pallet { /// Populates `RandomnessResults` due this epoch with BABE epoch randomness #[pallet::call_index(0)] #[pallet::weight(( - SubstrateWeight::::set_babe_randomness_results(), + T::WeightInfo::set_babe_randomness_results(), DispatchClass::Mandatory ))] pub fn set_babe_randomness_results(origin: OriginFor) -> DispatchResultWithPostInfo { @@ -305,7 +307,7 @@ pub mod pallet { } // Verify VRF output included by block author and set it in storage vrf::verify_and_set_output::(); - SubstrateWeight::::on_initialize() + T::WeightInfo::on_initialize() } fn on_finalize(_now: BlockNumberFor) { // Ensure the mandatory inherent was included in the block or the block is invalid diff --git a/pallets/randomness/src/mock.rs b/pallets/randomness/src/mock.rs index aeaa64196b..451f4cb9ca 100644 --- a/pallets/randomness/src/mock.rs +++ b/pallets/randomness/src/mock.rs @@ -141,6 +141,7 @@ impl Config for Test { type MaxBlockDelay = MaxBlockDelay; type BlockExpirationDelay = MaxBlockDelay; type EpochExpirationDelay = MaxBlockDelay; + type WeightInfo = pallet_randomness::weights::SubstrateWeight; } pub(crate) fn events() -> Vec> { diff --git a/pallets/randomness/src/types.rs b/pallets/randomness/src/types.rs index 9c91b2916a..8aaf90dde1 100644 --- a/pallets/randomness/src/types.rs +++ b/pallets/randomness/src/types.rs @@ -22,7 +22,7 @@ use sp_core::{H160, H256}; use sp_runtime::traits::{CheckedAdd, CheckedSub, Saturating}; use sp_std::vec::Vec; -#[derive(PartialEq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Copy, Clone, Encode, Decode, TypeInfo)] #[scale_info(skip_type_params(T))] /// Shared request info, a subset of `RequestInfo` pub enum RequestType { @@ -32,7 +32,8 @@ pub enum RequestType { Local(T::BlockNumber), } -#[derive(PartialEq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Copy, Clone, Encode, Decode, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] #[scale_info(skip_type_params(T))] /// Type of request /// Represents a request for the most recent randomness at or after the inner first field @@ -111,7 +112,7 @@ impl RandomnessResult { } } -#[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Clone, Encode, Decode, TypeInfo)] /// Input arguments to request randomness pub struct Request { /// Fee is returned to this account upon execution @@ -130,6 +131,18 @@ pub struct Request { pub info: Info, } +impl core::fmt::Debug for Request { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Request") + .field("refund_address", &self.refund_address) + .field("contract_address", &self.refund_address) + .field("gas_limit", &self.gas_limit) + .field("num_words", &self.num_words) + .field("salt", &self.salt) + .finish() + } +} + impl From, RequestType>> for Request, RequestInfo> { @@ -288,7 +301,8 @@ impl Request, RequestInfo> { } } -#[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Clone, Encode, Decode, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] #[scale_info(skip_type_params(T))] pub struct RequestState { /// Underlying request @@ -297,7 +311,8 @@ pub struct RequestState { pub deposit: BalanceOf, } -#[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Clone, Encode, Decode, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] #[scale_info(skip_type_params(T))] /// Data required to make the subcallback and finish fulfilling the request pub struct FulfillArgs { diff --git a/pallets/xcm-transactor/src/lib.rs b/pallets/xcm-transactor/src/lib.rs index 0877ad2c90..57d47ec677 100644 --- a/pallets/xcm-transactor/src/lib.rs +++ b/pallets/xcm-transactor/src/lib.rs @@ -181,7 +181,17 @@ pub mod pallet { /// Stores the information to be able to issue a transact operation in another chain use an /// asset as fee payer. - #[derive(Default, Clone, Encode, Decode, RuntimeDebug, Eq, PartialEq, scale_info::TypeInfo)] + #[derive( + Default, + Clone, + Encode, + Decode, + MaxEncodedLen, + RuntimeDebug, + Eq, + PartialEq, + scale_info::TypeInfo, + )] pub struct RemoteTransactInfoWithMaxWeight { /// Extra weight that transacting a call in a destination chain adds /// Extra weight involved when transacting without DescendOrigin diff --git a/precompiles/assets-erc20/src/eip2612.rs b/precompiles/assets-erc20/src/eip2612.rs index 29d98b5872..e25aa9a031 100644 --- a/precompiles/assets-erc20/src/eip2612.rs +++ b/precompiles/assets-erc20/src/eip2612.rs @@ -197,7 +197,8 @@ where r: H256, s: H256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; let owner: H160 = owner.into(); let spender: H160 = spender.into(); @@ -251,7 +252,8 @@ where handle: &mut impl PrecompileHandle, owner: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; let owner: H160 = owner.into(); @@ -264,7 +266,12 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: AssetMetadata: + // Blake2_128(16) + AssetId(16) + AssetMetadata[deposit(16) + name(StringLimit) + // + symbol(StringLimit) + decimals(1) + is_frozen(1)] + handle.record_db_read::( + 50 + (2 * >::StringLimit::get()) as usize, + )?; let domain_separator: H256 = Self::compute_domain_separator(handle.code_address(), asset_id).into(); diff --git a/precompiles/assets-erc20/src/lib.rs b/precompiles/assets-erc20/src/lib.rs index f0a1956e66..c4e82bf345 100644 --- a/precompiles/assets-erc20/src/lib.rs +++ b/precompiles/assets-erc20/src/lib.rs @@ -33,7 +33,7 @@ use precompile_utils::prelude::*; use sp_runtime::traits::Bounded; use sp_std::vec::Vec; -use sp_core::{H160, H256, U256}; +use sp_core::{MaxEncodedLen, H160, H256, U256}; use sp_std::{ convert::{TryFrom, TryInto}, marker::PhantomData, @@ -161,7 +161,9 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; Ok(pallet_assets::Pallet::::total_issuance(asset_id).into()) } @@ -173,7 +175,11 @@ where handle: &mut impl PrecompileHandle, who: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Account: + // Blake2_128(16) + AssetId(16) + Blake2_128(16) + AccountId(20) + AssetAccount(19 + Extra) + handle.record_db_read::( + 87 + >::Extra::max_encoded_len(), + )?; let who: H160 = who.into(); @@ -195,7 +201,9 @@ where owner: Address, spender: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Approvals: + // Blake2_128(16) + AssetId(16) + (2 * Blake2_128(16) + AccountId(20)) + Approval(32) + handle.record_db_read::(136)?; let owner: H160 = owner.into(); let spender: H160 = spender.into(); @@ -252,8 +260,9 @@ where let amount: BalanceOf = value.try_into().unwrap_or_else(|_| Bounded::max_value()); - // Allowance read - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Approvals: + // Blake2_128(16) + AssetId(16) + (2 * Blake2_128(16) + AccountId(20)) + Approval(32) + handle.record_db_read::(136)?; // If previous approval exists, we need to clean it if pallet_assets::Pallet::::allowance(asset_id, &owner, &spender) @@ -389,7 +398,12 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Metadata: + // Blake2_128(16) + AssetId(16) + AssetMetadata[deposit(16) + name(StringLimit) + // + symbol(StringLimit) + decimals(1) + is_frozen(1)] + handle.record_db_read::( + 50 + (2 * >::StringLimit::get()) as usize, + )?; let name = pallet_assets::Pallet::::name(asset_id) .as_slice() @@ -404,7 +418,12 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Metadata: + // Blake2_128(16) + AssetId(16) + AssetMetadata[deposit(16) + name(StringLimit) + // + symbol(StringLimit) + decimals(1) + is_frozen(1)] + handle.record_db_read::( + 50 + (2 * >::StringLimit::get()) as usize, + )?; let symbol = pallet_assets::Pallet::::symbol(asset_id) .as_slice() @@ -419,7 +438,12 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Metadata: + // Blake2_128(16) + AssetId(16) + AssetMetadata[deposit(16) + name(StringLimit) + // + symbol(StringLimit) + decimals(1) + is_frozen(1)] + handle.record_db_read::( + 50 + (2 * >::StringLimit::get()) as usize, + )?; Ok(pallet_assets::Pallet::::decimals( asset_id, @@ -432,7 +456,9 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; let owner: H160 = pallet_assets::Pallet::::owner(asset_id) .ok_or(revert("No owner set"))? @@ -447,7 +473,9 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; let issuer: H160 = pallet_assets::Pallet::::issuer(asset_id) .ok_or(revert("No issuer set"))? @@ -462,7 +490,9 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; let admin: H160 = pallet_assets::Pallet::::admin(asset_id) .ok_or(revert("No admin set"))? @@ -477,7 +507,9 @@ where asset_id: AssetIdOf, handle: &mut impl PrecompileHandle, ) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; let freezer: H160 = pallet_assets::Pallet::::freezer(asset_id) .ok_or(revert("No freezer set"))? diff --git a/precompiles/assets-erc20/src/mock.rs b/precompiles/assets-erc20/src/mock.rs index f7c4d267fd..0f9dc2d552 100644 --- a/precompiles/assets-erc20/src/mock.rs +++ b/precompiles/assets-erc20/src/mock.rs @@ -175,10 +175,16 @@ pub type Precompiles = PrecompileSetBuilder< pub type LocalPCall = Erc20AssetsPrecompileSetCall; pub type ForeignPCall = Erc20AssetsPrecompileSetCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -199,6 +205,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } type ForeignAssetInstance = pallet_assets::Instance1; diff --git a/precompiles/author-mapping/src/lib.rs b/precompiles/author-mapping/src/lib.rs index 6fc8855a22..5b66d03b72 100644 --- a/precompiles/author-mapping/src/lib.rs +++ b/precompiles/author-mapping/src/lib.rs @@ -160,7 +160,9 @@ where #[precompile::public("nimbusIdOf(address)")] #[precompile::view] fn nimbus_id_of(handle: &mut impl PrecompileHandle, address: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: NimbusLookup: + // Blake2_128(16) + AccountId(20) + NimbusId(32) + handle.record_db_read::(68)?; let account = Runtime::AddressMapping::into_account_id(address.0); let nimbus_id = pallet_author_mapping::Pallet::::nimbus_id_of(&account) @@ -172,7 +174,9 @@ where #[precompile::public("addressOf(bytes32)")] #[precompile::view] fn address_of(handle: &mut impl PrecompileHandle, nimbus_id: H256) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: MappingWithDeposit: + // Blake2_128(16) + NimbusId(32) + RegistrationInfo(20 + 16 + VrfId(32)) + handle.record_db_read::(116)?; let nimbus_id = sp_core::sr25519::Public::unchecked_from(nimbus_id); let nimbus_id: NimbusId = nimbus_id.into(); @@ -187,7 +191,9 @@ where #[precompile::public("keysOf(bytes32)")] #[precompile::view] fn keys_of(handle: &mut impl PrecompileHandle, nimbus_id: H256) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: MappingWithDeposit: + // Blake2_128(16) + NimbusId(32) + RegistrationInfo(20 + 16 + VrfId(32)) + handle.record_db_read::(116)?; let nimbus_id = sp_core::sr25519::Public::unchecked_from(nimbus_id); let nimbus_id: NimbusId = nimbus_id.into(); diff --git a/precompiles/author-mapping/src/mock.rs b/precompiles/author-mapping/src/mock.rs index 5b626fb6c5..45bfa45c80 100644 --- a/precompiles/author-mapping/src/mock.rs +++ b/precompiles/author-mapping/src/mock.rs @@ -103,10 +103,16 @@ pub type PCall = AuthorMappingPrecompileCall; mock_account!(AuthorMappingAccount, |_| MockAccount::from_u64(1)); +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -127,6 +133,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/balances-erc20/src/eip2612.rs b/precompiles/balances-erc20/src/eip2612.rs index babb7747d6..e42a7e9c6c 100644 --- a/precompiles/balances-erc20/src/eip2612.rs +++ b/precompiles/balances-erc20/src/eip2612.rs @@ -98,7 +98,8 @@ where r: H256, s: H256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; let owner: H160 = owner.into(); let spender: H160 = spender.into(); @@ -158,7 +159,8 @@ where } pub(crate) fn nonces(handle: &mut impl PrecompileHandle, owner: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; let owner: H160 = owner.into(); @@ -166,7 +168,8 @@ where } pub(crate) fn domain_separator(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ChainId + handle.record_db_read::(8)?; Ok(Self::compute_domain_separator(handle.context().address).into()) } diff --git a/precompiles/balances-erc20/src/lib.rs b/precompiles/balances-erc20/src/lib.rs index 7d04abbcc7..ba4b70327f 100644 --- a/precompiles/balances-erc20/src/lib.rs +++ b/precompiles/balances-erc20/src/lib.rs @@ -192,7 +192,8 @@ where #[precompile::public("totalSupply()")] #[precompile::view] fn total_supply(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // TotalIssuance: Balance(16) + handle.record_db_read::(16)?; Ok(pallet_balances::Pallet::::total_issuance().into()) } @@ -200,7 +201,9 @@ where #[precompile::public("balanceOf(address)")] #[precompile::view] fn balance_of(handle: &mut impl PrecompileHandle, owner: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // frame_system::Account: + // Blake2128(16) + AccountId(20) + AccountInfo ((4 * 4) + AccountData(16 * 4)) + handle.record_db_read::(116)?; let owner: H160 = owner.into(); let owner: Runtime::AccountId = Runtime::AddressMapping::into_account_id(owner); @@ -215,7 +218,9 @@ where owner: Address, spender: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // frame_system::ApprovesStorage: + // (2 * (Blake2128(16) + AccountId(20)) + Balanceof(16) + handle.record_db_read::(88)?; let owner: H160 = owner.into(); let spender: H160 = spender.into(); @@ -305,7 +310,9 @@ where to: Address, value: U256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // frame_system::ApprovesStorage: + // (2 * (Blake2128(16) + AccountId(20)) + Balanceof(16) + handle.record_db_read::(88)?; handle.record_cost(RuntimeHelper::::db_write_gas_cost())?; handle.record_log_costs_manual(3, 32)?; diff --git a/precompiles/balances-erc20/src/mock.rs b/precompiles/balances-erc20/src/mock.rs index f5694ba60e..8b04a0d86e 100644 --- a/precompiles/balances-erc20/src/mock.rs +++ b/precompiles/balances-erc20/src/mock.rs @@ -96,10 +96,16 @@ pub type Precompiles = PrecompileSetBuilder< pub type PCall = Erc20BalancesPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); - pub PrecompilesValue: Precompiles = Precompiles::new(); - pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub PrecompilesValue: Precompiles = Precompiles::new(); + pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -120,6 +126,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } // Configure a mock runtime to test the pallet. diff --git a/precompiles/batch/src/mock.rs b/precompiles/batch/src/mock.rs index 324397198e..e82935436f 100644 --- a/precompiles/batch/src/mock.rs +++ b/precompiles/batch/src/mock.rs @@ -117,10 +117,16 @@ pub type PCall = BatchPrecompileCall; mock_account!(Batch, |_| MockAccount::from_u64(1)); mock_account!(Revert, |_| MockAccount::from_u64(2)); +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -141,6 +147,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/call-permit/src/lib.rs b/precompiles/call-permit/src/lib.rs index 6e500bcdb0..cb99912655 100644 --- a/precompiles/call-permit/src/lib.rs +++ b/precompiles/call-permit/src/lib.rs @@ -130,7 +130,6 @@ where pub fn dispatch_inherent_cost() -> u64 { 3_000 // cost of ECRecover precompile for reference - + RuntimeHelper::::db_read_gas_cost() * 2 // we read nonce and timestamp + RuntimeHelper::::db_write_gas_cost() // we write nonce } @@ -149,6 +148,11 @@ where r: H256, s: H256, ) -> EvmResult { + // Now: 8 + handle.record_db_read::(8)?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; + handle.record_cost(Self::dispatch_inherent_cost())?; let from: H160 = from.into(); @@ -234,7 +238,8 @@ where #[precompile::public("nonces(address)")] #[precompile::view] fn nonces(handle: &mut impl PrecompileHandle, owner: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32) + handle.record_db_read::(104)?; let owner: H160 = owner.into(); @@ -246,7 +251,8 @@ where #[precompile::public("DOMAIN_SEPARATOR()")] #[precompile::view] fn domain_separator(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ChainId + handle.record_db_read::(8)?; let domain_separator: H256 = Self::compute_domain_separator(handle.context().address).into(); diff --git a/precompiles/call-permit/src/mock.rs b/precompiles/call-permit/src/mock.rs index 0e1575f170..eeebe10e0b 100644 --- a/precompiles/call-permit/src/mock.rs +++ b/precompiles/call-permit/src/mock.rs @@ -132,6 +132,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = (); + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/collective/src/lib.rs b/precompiles/collective/src/lib.rs index 217b7f453b..9289c34397 100644 --- a/precompiles/collective/src/lib.rs +++ b/precompiles/collective/src/lib.rs @@ -149,7 +149,8 @@ where threshold: u32, proposal: BoundedBytes, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ProposalCount + handle.record_db_read::(4)?; let proposal: Vec<_> = proposal.into(); let proposal_length: u32 = proposal.len().try_into().map_err(|_| { @@ -289,7 +290,10 @@ where #[precompile::public("proposals()")] #[precompile::view] fn proposals(handle: &mut impl PrecompileHandle) -> EvmResult> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Proposals: BoundedVec(32 * MaxProposals) + handle.record_db_read::( + 32 * (>::MaxProposals::get() as usize), + )?; let proposals = pallet_collective::Pallet::::proposals(); let proposals: Vec<_> = proposals.into_iter().map(|hash| hash.into()).collect(); @@ -300,7 +304,10 @@ where #[precompile::public("members()")] #[precompile::view] fn members(handle: &mut impl PrecompileHandle) -> EvmResult> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Members: Vec(20 * MaxMembers) + handle.record_db_read::( + 20 * (>::MaxProposals::get() as usize), + )?; let members = pallet_collective::Pallet::::members(); let members: Vec<_> = members.into_iter().map(|id| Address(id.into())).collect(); @@ -311,7 +318,10 @@ where #[precompile::public("isMember(address)")] #[precompile::view] fn is_member(handle: &mut impl PrecompileHandle, account: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Members: Vec(20 * MaxMembers) + handle.record_db_read::( + 20 * (>::MaxProposals::get() as usize), + )?; let account = Runtime::AddressMapping::into_account_id(account.into()); @@ -323,7 +333,8 @@ where #[precompile::public("prime()")] #[precompile::view] fn prime(handle: &mut impl PrecompileHandle) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Prime + handle.record_db_read::(20)?; let prime = pallet_collective::Pallet::::prime() .map(|prime| prime.into()) diff --git a/precompiles/collective/src/mock.rs b/precompiles/collective/src/mock.rs index 91e03a76d2..b493c83391 100644 --- a/precompiles/collective/src/mock.rs +++ b/precompiles/collective/src/mock.rs @@ -111,10 +111,16 @@ pub type Precompiles = PrecompileSetBuilder< pub type PCall = CollectivePrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -135,6 +141,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/conviction-voting/src/lib.rs b/precompiles/conviction-voting/src/lib.rs index aa04b11c4b..6cab8c4df1 100644 --- a/precompiles/conviction-voting/src/lib.rs +++ b/precompiles/conviction-voting/src/lib.rs @@ -26,7 +26,7 @@ use pallet_conviction_voting::{ }; use pallet_evm::{AddressMapping, Log}; use precompile_utils::prelude::*; -use sp_core::{H160, H256, U256}; +use sp_core::{Get, MaxEncodedLen, H160, H256, U256}; use sp_runtime::traits::StaticLookup; use sp_std::marker::PhantomData; use sp_std::vec::Vec; @@ -112,6 +112,14 @@ where ::RuntimeCall: From>, IndexOf: TryFrom + TryInto, ClassOf: TryFrom + TryInto, + ::Polls: Polling< + Tally< + <::Currency as Currency< + ::AccountId, + >>::Balance, + ::MaxTurnout, + >, + >, { /// Internal helper function for vote* extrinsics exposed in this precompile. fn vote( @@ -437,7 +445,8 @@ where who: Address, track_id: u16, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // VotingFor: Twox64Concat(8) + 20 + Twox64Concat(8) + TransInfo::Id(2) + VotingOf + handle.record_db_read::(38 + VotingOf::::max_encoded_len())?; let who = Runtime::AddressMapping::into_account_id(who.into()); let class = Self::u16_to_track_id(track_id).in_field("trackId")?; @@ -453,7 +462,18 @@ where handle: &mut impl PrecompileHandle, who: Address, ) -> EvmResult> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ClassLocksFor: Twox64Concat(8) + 20 + BoundedVec(TransInfo::Id(2) * ClassCountOf) + handle.record_db_read::( + 28 + ((2 * frame_support::traits::ClassCountOf::< + ::Polls, + Tally< + <::Currency as Currency< + ::AccountId, + >>::Balance, + ::MaxTurnout, + >, + >::get()) as usize), + )?; let who = Runtime::AddressMapping::into_account_id(who.into()); diff --git a/precompiles/conviction-voting/src/mock.rs b/precompiles/conviction-voting/src/mock.rs index 99bb0b0836..4597725774 100644 --- a/precompiles/conviction-voting/src/mock.rs +++ b/precompiles/conviction-voting/src/mock.rs @@ -101,10 +101,16 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } pub type Precompiles = @@ -130,6 +136,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/crowdloan-rewards/src/lib.rs b/precompiles/crowdloan-rewards/src/lib.rs index 4382535524..234ef29bd5 100644 --- a/precompiles/crowdloan-rewards/src/lib.rs +++ b/precompiles/crowdloan-rewards/src/lib.rs @@ -60,7 +60,9 @@ where #[precompile::public("is_contributor(address)")] #[precompile::view] fn is_contributor(handle: &mut impl PrecompileHandle, contributor: Address) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; // accounts_payable + // AccountsPayable: Blake2128(16) + 20 + RewardInfo(16 + 16 + UnBoundedVec) + // TODO RewardInfo.contributed_relay_addresses is unbounded, we set a safe length of 100. + handle.record_db_read::(3268)?; let contributor: H160 = contributor.into(); @@ -88,7 +90,9 @@ where handle: &mut impl PrecompileHandle, contributor: Address, ) -> EvmResult<(U256, U256)> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; // accounts_payable + // AccountsPayable: Blake2128(16) + 20 + RewardInfo(16 + 16 + UnBoundedVec) + // TODO RewardInfo.contributed_relay_addresses is unbounded, we set a safe length of 100. + handle.record_db_read::(3268)?; let contributor: H160 = contributor.into(); diff --git a/precompiles/crowdloan-rewards/src/mock.rs b/precompiles/crowdloan-rewards/src/mock.rs index d99f0b0bb5..17d5b4b81f 100644 --- a/precompiles/crowdloan-rewards/src/mock.rs +++ b/precompiles/crowdloan-rewards/src/mock.rs @@ -128,10 +128,16 @@ pub type Precompiles = pub type PCall = CrowdloanRewardsPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -152,6 +158,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/gmp/src/lib.rs b/precompiles/gmp/src/lib.rs index f0bc5a5f1b..41b37de842 100644 --- a/precompiles/gmp/src/lib.rs +++ b/precompiles/gmp/src/lib.rs @@ -81,8 +81,13 @@ where // 1 read for enabled flag // 2 reads for contract addresses // 2500 as fudge for computation, esp. payload decoding (TODO: benchmark?) - let initial_gas = 2500 + 3 * RuntimeHelper::::db_read_gas_cost(); - handle.record_cost(initial_gas)?; + handle.record_cost(2500)?; + // CoreAddress: AccountId(20) + handle.record_db_read::(20)?; + // BridgeAddress: AccountId(20) + handle.record_db_read::(20)?; + // PrecompileEnabled: AccountId(1) + handle.record_db_read::(1)?; ensure_enabled()?; diff --git a/precompiles/gmp/src/mock.rs b/precompiles/gmp/src/mock.rs index e352747020..b13560d765 100644 --- a/precompiles/gmp/src/mock.rs +++ b/precompiles/gmp/src/mock.rs @@ -236,10 +236,16 @@ pub type PCall = GmpPrecompileCall; mock_account!(Batch, |_| MockAccount::from_u64(1)); mock_account!(Revert, |_| MockAccount::from_u64(2)); +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -260,6 +266,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/pallet-democracy/src/lib.rs b/precompiles/pallet-democracy/src/lib.rs index 6ac516db07..f08e51d2a9 100644 --- a/precompiles/pallet-democracy/src/lib.rs +++ b/precompiles/pallet-democracy/src/lib.rs @@ -27,7 +27,7 @@ use pallet_democracy::{ use pallet_evm::AddressMapping; use pallet_preimage::Call as PreimageCall; use precompile_utils::prelude::*; -use sp_core::{H160, H256, U256}; +use sp_core::{Get, H160, H256, U256}; use sp_runtime::traits::{Hash, StaticLookup}; use sp_std::{ convert::{TryFrom, TryInto}, @@ -96,7 +96,9 @@ where #[precompile::view] fn public_prop_count(handle: &mut impl PrecompileHandle) -> EvmResult { // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: PublicPropCount + // max encoded len: u32(4) + handle.record_db_read::(4)?; let prop_count = DemocracyOf::::public_prop_count(); log::trace!(target: "democracy-precompile", "Prop count from pallet is {:?}", prop_count); @@ -113,7 +115,10 @@ where let prop_index = prop_index.converted(); // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: DepositOf + // max encoded len: Twox64(8) + PropIndex u32(4) + + // BalanceOf(16) + BoundedVec (20 * MaxDeposits) + handle.record_db_read::((20 * ::get() as usize) + 28)?; let deposit = DemocracyOf::::deposit_of(prop_index) .ok_or_else(|| revert("No such proposal in pallet democracy"))? .1; @@ -131,7 +136,9 @@ where #[precompile::view] fn lowest_unbaked(handle: &mut impl PrecompileHandle) -> EvmResult { // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: LowestUnbaked + // max encoded len: ReferendumIndex u32(4) + handle.record_db_read::(4)?; let lowest_unbaked = DemocracyOf::::lowest_unbaked(); log::trace!( target: "democracy-precompile", @@ -147,7 +154,10 @@ where handle: &mut impl PrecompileHandle, ref_index: u32, ) -> EvmResult<(U256, H256, u8, U256, U256, U256, U256)> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: ReferendumInfoOf + // max encoded len: Twox64(8) + ReferendumIndex u32(4) + + // ReferendumInfo (enum(1) + end(4) + proposal(128) + threshold(1) + delay(4) + tally(3*16)) + handle.record_db_read::(186)?; let ref_status = match DemocracyOf::::referendum_info(ref_index) { Some(ReferendumInfo::Ongoing(ref_status)) => ref_status, Some(ReferendumInfo::Finished { .. }) => Err(revert("Referendum is finished"))?, @@ -177,7 +187,10 @@ where handle: &mut impl PrecompileHandle, ref_index: u32, ) -> EvmResult<(bool, U256)> { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: ReferendumInfoOf + // max encoded len: Twox64(8) + ReferendumIndex u32(4) + + // ReferendumInfo (enum(1) + end(4) + proposal(128) + threshold(1) + delay(4) + tally(3*16)) + handle.record_db_read::(186)?; let (approved, end) = match DemocracyOf::::referendum_info(ref_index) { Some(ReferendumInfo::Ongoing(_)) => Err(revert("Referendum is ongoing"))?, Some(ReferendumInfo::Finished { approved, end }) => (approved, end), @@ -193,7 +206,9 @@ where handle.record_log_costs_manual(2, 32)?; // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: PublicPropCount + // max encoded len: PropIndex u32(4) + handle.record_db_read::(4)?; let prop_count = DemocracyOf::::public_prop_count(); let value = Self::u256_to_amount(value).in_field("value")?; @@ -204,8 +219,9 @@ where ); // This forces it to have the proposal in pre-images. - // TODO: REVISIT - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Storage item: StatusFor + // max encoded len: Hash(32) + RequestStatus(enum(1) + deposit(1+20+16) + count(4) + len(5)) + handle.record_db_read::(79)?; let len = ::Preimages::len(&proposal_hash).ok_or({ RevertReason::custom("Failure in preimage fetch").in_field("proposal_hash") })?; @@ -457,9 +473,11 @@ where // To mimic imminent preimage behavior, we need to check whether the preimage // has been requested - // is_requested implies db read - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let proposal_hash = ::Hashing::hash(&encoded_proposal); + // is_requested implies db read + // Storage item: StatusFor + // max encoded len: Hash(32) + RequestStatus(enum(1) + deposit(1+20+16) + count(4) + len(5)) + handle.record_db_read::(79)?; if !<::Preimages as QueryPreimage>::is_requested( &proposal_hash.into(), ) { diff --git a/precompiles/pallet-democracy/src/mock.rs b/precompiles/pallet-democracy/src/mock.rs index 2b2c34220c..3abb6da83c 100644 --- a/precompiles/pallet-democracy/src/mock.rs +++ b/precompiles/pallet-democracy/src/mock.rs @@ -97,10 +97,16 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } pub type Precompiles = @@ -126,6 +132,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/parachain-staking/src/lib.rs b/precompiles/parachain-staking/src/lib.rs index 9ef0f883d6..b9ab2d68a5 100644 --- a/precompiles/parachain-staking/src/lib.rs +++ b/precompiles/parachain-staking/src/lib.rs @@ -59,9 +59,7 @@ where #[precompile::public("minDelegation()")] #[precompile::public("min_delegation()")] #[precompile::view] - fn min_delegation(handle: &mut impl PrecompileHandle) -> EvmResult { - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + fn min_delegation(_handle: &mut impl PrecompileHandle) -> EvmResult { let min_nomination: u128 = <::MinDelegation as Get< BalanceOf, @@ -77,8 +75,8 @@ where #[precompile::view] fn points(handle: &mut impl PrecompileHandle, round: Convert) -> EvmResult { let round = round.converted(); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // AccountsPayable: Twox64Concat(8) + RoundIndex(4) + RewardPoint(4) + handle.record_db_read::(16)?; let points: u32 = pallet_parachain_staking::Pallet::::points(round); Ok(points) @@ -91,7 +89,9 @@ where round: u32, candidate: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // AccountsPayable: Twox64Concat(8) + RoundIndex(4) + Twox64Concat(8) + AccountId(20) + // + RewardPoint(4) + handle.record_db_read::(44)?; let candidate = Runtime::AddressMapping::into_account_id(candidate.0); @@ -104,8 +104,10 @@ where #[precompile::public("candidate_count()")] #[precompile::view] fn candidate_count(handle: &mut impl PrecompileHandle) -> EvmResult { + // CandidatePool: UnBoundedVec(AccountId(20) + Balance(16)) + // TODO CandidatePool is unbounded, we account for a theoretical 200 pool. + handle.record_db_read::(7200)?; // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let candidate_count: u32 = >::candidate_pool() .0 .len() as u32; @@ -117,8 +119,8 @@ where #[precompile::public("round()")] #[precompile::view] fn round(handle: &mut impl PrecompileHandle) -> EvmResult { - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Round: RoundInfo(RoundIndex(4) + BlockNumber(4) + 4) + handle.record_db_read::(12)?; let round: u32 = >::round().current; Ok(round) @@ -132,9 +134,8 @@ where candidate: Address, ) -> EvmResult { let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: Twox64Concat(8) + AccountId(20) + CandidateMetadata(105) + handle.record_db_read::(133)?; let result = if let Some(state) = >::candidate_info(&candidate) { @@ -164,7 +165,17 @@ where handle: &mut impl PrecompileHandle, candidate: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // AutoCompoundingDelegations: + // Blake2128(16) + AccountId(20) + // + BoundedVec( + // AutoCompoundConfig * (MaxTopDelegationsPerCandidate + MaxBottomDelegationsPerCandidate) + // ) + handle.record_db_read::( + 36 + ( + 22 * (::MaxTopDelegationsPerCandidate::get() + + ::MaxBottomDelegationsPerCandidate::get()) + as usize), + )?; let candidate = Runtime::AddressMapping::into_account_id(candidate.0); @@ -183,9 +194,12 @@ where delegator: Address, ) -> EvmResult { let delegator = Runtime::AddressMapping::into_account_id(delegator.0); - - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: + // Twox64Concat(8) + AccountId(20) + Delegator(56 + MaxDelegationsPerDelegator) + handle.record_db_read::( + 84 + (::MaxDelegationsPerDelegator::get() + as usize), + )?; let result = if let Some(state) = >::delegator_state(&delegator) { @@ -214,8 +228,11 @@ where #[precompile::public("selected_candidates()")] #[precompile::view] fn selected_candidates(handle: &mut impl PrecompileHandle) -> EvmResult> { - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // TotalSelected + handle.record_db_read::(4)?; + let total_selected = pallet_parachain_staking::Pallet::::total_selected(); + // SelectedCandidates: total_selected * AccountId(20) + handle.record_db_read::(20 * (total_selected as usize))?; let selected_candidates: Vec
= pallet_parachain_staking::Pallet::::selected_candidates() .into_iter() @@ -232,8 +249,12 @@ where delegator: Address, candidate: Address, ) -> EvmResult { - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // DelegatorState: + // Twox64Concat(8) + AccountId(20) + Delegator(56 + MaxDelegationsPerDelegator) + handle.record_db_read::( + 84 + (::MaxDelegationsPerDelegator::get() + as usize), + )?; let (candidate, delegator) = ( Runtime::AddressMapping::into_account_id(candidate.0), Runtime::AddressMapping::into_account_id(delegator.0), @@ -266,9 +287,14 @@ where Runtime::AddressMapping::into_account_id(candidate.0), Runtime::AddressMapping::into_account_id(delegator.0), ); - - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // TopDelegations: + // Twox64Concat(8) + AccountId(20) + Balance(16) + // + (AccountId(20) + Balance(16) * MaxTopDelegationsPerCandidate) + handle.record_db_read::( + 44 + ((36 + * ::MaxTopDelegationsPerCandidate::get( + )) as usize), + )?; let is_in_top_delegations = pallet_parachain_staking::Pallet::::top_delegations( &candidate, ) @@ -287,9 +313,12 @@ where #[precompile::view] fn is_delegator(handle: &mut impl PrecompileHandle, delegator: Address) -> EvmResult { let delegator = Runtime::AddressMapping::into_account_id(delegator.0); - - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // DelegatorState: + // Twox64Concat(8) + AccountId(20) + Delegator(56 + MaxDelegationsPerDelegator) + handle.record_db_read::( + 84 + (::MaxDelegationsPerDelegator::get() + as usize), + )?; let is_delegator = pallet_parachain_staking::Pallet::::is_delegator(&delegator); Ok(is_delegator) @@ -301,8 +330,8 @@ where fn is_candidate(handle: &mut impl PrecompileHandle, candidate: Address) -> EvmResult { let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: Twox64Concat(8) + AccountId(20) + CandidateMetadata(105) + handle.record_db_read::(133)?; let is_candidate = pallet_parachain_staking::Pallet::::is_candidate(&candidate); Ok(is_candidate) @@ -317,8 +346,11 @@ where ) -> EvmResult { let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // TotalSelected + handle.record_db_read::(4)?; + let total_selected = pallet_parachain_staking::Pallet::::total_selected(); + // SelectedCandidates: total_selected * AccountId(20) + handle.record_db_read::(20 * (total_selected as usize))?; let is_selected = pallet_parachain_staking::Pallet::::is_selected_candidate(&candidate); @@ -336,8 +368,18 @@ where let delegator = Runtime::AddressMapping::into_account_id(delegator.0); let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // DelegationScheduledRequests: + // Blake2128(16) + AccountId(20) + // + Vec( + // ScheduledRequest(20 + 4 + DelegationAction(18)) + // * (MaxTopDelegationsPerCandidate + MaxBottomDelegationsPerCandidate) + // ) + handle.record_db_read::( + 36 + ( + 42 * (::MaxTopDelegationsPerCandidate::get() + + ::MaxBottomDelegationsPerCandidate::get()) + as usize), + )?; // If we are not able to get delegator state, we return false // Users can call `is_delegator` to determine when this happens @@ -357,8 +399,8 @@ where ) -> EvmResult { let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: Twox64Concat(8) + AccountId(20) + CandidateMetadata(105) + handle.record_db_read::(133)?; // If we are not able to get delegator state, we return false // Users can call `is_candidate` to determine when this happens @@ -387,8 +429,8 @@ where ) -> EvmResult { let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: Twox64Concat(8) + AccountId(20) + CandidateMetadata(105) + handle.record_db_read::(133)?; // If we are not able to get candidate metadata, we return false // Users can call `is_candidate` to determine when this happens @@ -418,8 +460,17 @@ where let delegator = Runtime::AddressMapping::into_account_id(delegator.0); let candidate = Runtime::AddressMapping::into_account_id(candidate.0); - // Fetch info. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // AutoCompoundingDelegations: + // Blake2128(16) + AccountId(20) + // + BoundedVec( + // AutoCompoundConfig * (MaxTopDelegationsPerCandidate + MaxBottomDelegationsPerCandidate) + // ) + handle.record_db_read::( + 36 + ( + 22 * (::MaxTopDelegationsPerCandidate::get() + + ::MaxBottomDelegationsPerCandidate::get()) + as usize), + )?; let value = >::delegation_auto_compound( &candidate, &delegator, @@ -878,7 +929,12 @@ where handle: &mut impl PrecompileHandle, delegator: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // DelegatorState: + // Twox64Concat(8) + AccountId(20) + Delegator(56 + MaxDelegationsPerDelegator) + handle.record_db_read::( + 84 + (::MaxDelegationsPerDelegator::get() + as usize), + )?; let delegator = Runtime::AddressMapping::into_account_id(delegator.0); @@ -895,7 +951,8 @@ where handle: &mut impl PrecompileHandle, candidate: Address, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // CandidateInfo: Twox64Concat(8) + AccountId(20) + CandidateMetadata(105) + handle.record_db_read::(133)?; let candidate = Runtime::AddressMapping::into_account_id(candidate.0); diff --git a/precompiles/parachain-staking/src/mock.rs b/precompiles/parachain-staking/src/mock.rs index d51fdec148..b74576eb91 100644 --- a/precompiles/parachain-staking/src/mock.rs +++ b/precompiles/parachain-staking/src/mock.rs @@ -104,10 +104,16 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } pub type Precompiles = @@ -133,6 +139,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/precompile-registry/src/lib.rs b/precompiles/precompile-registry/src/lib.rs index 3fd42d98d6..a6772357f2 100644 --- a/precompiles/precompile-registry/src/lib.rs +++ b/precompiles/precompile-registry/src/lib.rs @@ -43,7 +43,11 @@ where #[precompile::view] fn is_precompile(handle: &mut impl PrecompileHandle, address: Address) -> EvmResult { // We consider the precompile set is optimized to do at most one storage read. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // In the case of moonbeam, the storage item that can be read is pallet_asset::Asset + // (TODO make it more generic, maybe add a const generic on PrecompileRegistry type) + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; is_precompile_or_fail::(address.0, handle.remaining_gas()) } @@ -54,7 +58,11 @@ where address: Address, ) -> EvmResult { // We consider the precompile set is optimized to do at most one storage read. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // In the case of moonbeam, the storage item that can be read is pallet_asset::Asset + // (TODO make it more generic, maybe add a const generic on PrecompileRegistry type) + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; match ::get() .is_active_precompile(address.0, handle.remaining_gas()) { @@ -67,17 +75,23 @@ where #[precompile::public("updateAccountCode(address)")] fn update_account_code(handle: &mut impl PrecompileHandle, address: Address) -> EvmResult<()> { - // We consider the precompile set is optimized to do at most one storage read. - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; - - // We will write into the account code. - handle.record_cost(RuntimeHelper::::db_write_gas_cost())?; - // Prevent touching addresses that are not precompiles. + // + // We consider the precompile set is optimized to do at most one storage read. + // In the case of moonbeam, the storage item that can be read is pallet_asset::Asset + // (TODO make it more generic, maybe add a const generic on PrecompileRegistry type) + // Storage item: Asset: + // Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15) + handle.record_db_read::(175)?; if !is_precompile_or_fail::(address.0, handle.remaining_gas())? { return Err(revert("provided address is not a precompile")); } + // pallet_evm::create_account read storage item pallet_evm::AccountCodes + // + // AccountCodes: Blake2128(16) + H160(20) + Vec(5) + // We asume an existing precompile can hold at most 5 bytes worth of dummy code. + handle.record_db_read::(41)?; pallet_evm::Pallet::::create_account(address.0, DUMMY_CODE.to_vec()); Ok(()) diff --git a/precompiles/precompile-registry/src/mock.rs b/precompiles/precompile-registry/src/mock.rs index 0bfbd973d9..03e14e1ff8 100644 --- a/precompiles/precompile-registry/src/mock.rs +++ b/precompiles/precompile-registry/src/mock.rs @@ -133,6 +133,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = (); + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/preimage/src/mock.rs b/precompiles/preimage/src/mock.rs index 627a76f719..de80ce4b20 100644 --- a/precompiles/preimage/src/mock.rs +++ b/precompiles/preimage/src/mock.rs @@ -96,10 +96,16 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } pub type Precompiles = @@ -125,6 +131,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/proxy/src/lib.rs b/precompiles/proxy/src/lib.rs index d7ddf91742..e5cbe85874 100644 --- a/precompiles/proxy/src/lib.rs +++ b/precompiles/proxy/src/lib.rs @@ -25,7 +25,7 @@ use pallet_proxy::Call as ProxyCall; use pallet_proxy::Pallet as ProxyPallet; use precompile_utils::precompile_set::{self, AddressType, SelectorFilter}; use precompile_utils::prelude::*; -use sp_core::{H160, U256}; +use sp_core::{Get, H160, U256}; use sp_runtime::{ codec::Decode, traits::{ConstU32, StaticLookup, Zero}, @@ -175,7 +175,11 @@ where // See: https://github.com/PureStake/sr-moonbeam/issues/30 // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` and // filtered via CallFilter - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Proxies: + // Twox64Concat(8) + AccountId(20) + BoundedVec(ProxyDefinition * MaxProxies) + Balance(16) + handle.record_db_read::( + 28 + (29 * (::MaxProxies::get() as usize)) + 8, + )?; if ProxyPallet::::proxies(&origin) .0 .iter() @@ -329,7 +333,11 @@ where let real = Runtime::AddressMapping::into_account_id(real.into()); - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Proxies: + // Twox64Concat(8) + AccountId(20) + BoundedVec(ProxyDefinition * MaxProxies) + Balance(16) + handle.record_db_read::( + 28 + (29 * (::MaxProxies::get() as usize)) + 8, + )?; let is_proxy = ProxyPallet::::proxies(real) .0 .iter() @@ -345,22 +353,27 @@ where evm_subcall: EvmSubCall, ) -> EvmResult { // Check that we only perform proxy calls on behalf of externally owned accounts - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; - let AddressType::EOA = precompile_set::get_address_type::(real.into()) else { + let AddressType::EOA = precompile_set::get_address_type::(handle, real.into())? else { return Err(revert("real address must be EOA")); }; // Read proxy let real_account_id = Runtime::AddressMapping::into_account_id(real.into()); let who = Runtime::AddressMapping::into_account_id(handle.context().caller); - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // Proxies: + // Twox64Concat(8) + AccountId(20) + BoundedVec(ProxyDefinition * MaxProxies) + Balance(16) + handle.record_db_read::( + 28 + (29 * (::MaxProxies::get() as usize)) + 8, + )?; let def = pallet_proxy::Pallet::::find_proxy(&real_account_id, &who, force_proxy_type) .map_err(|_| RevertReason::custom("Not proxy"))?; frame_support::ensure!(def.delay.is_zero(), revert("Unannounced")); // Read subcall recipient code - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // AccountCodes: Blake2128(16) + H160(20) + Vec(5) + // decode_len reads the first 5 bytes to find the payload len under this key + handle.record_db_read::(41)?; let recipient_has_code = pallet_evm::AccountCodes::::decode_len(evm_subcall.to.0).unwrap_or(0) > 0; diff --git a/precompiles/proxy/src/mock.rs b/precompiles/proxy/src/mock.rs index 91cfdd1193..273c8f08b4 100644 --- a/precompiles/proxy/src/mock.rs +++ b/precompiles/proxy/src/mock.rs @@ -139,10 +139,16 @@ impl EnsureAddressOrigin for EnsureAddressAlways { } } +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { type FeeCalculator = (); @@ -162,6 +168,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/randomness/src/lib.rs b/precompiles/randomness/src/lib.rs index 570ad94a2a..60a7a9287d 100644 --- a/precompiles/randomness/src/lib.rs +++ b/precompiles/randomness/src/lib.rs @@ -21,7 +21,10 @@ extern crate alloc; use fp_evm::{Context, ExitReason, FeeCalculator, Log, PrecompileHandle}; -use frame_support::traits::Get; +use frame_support::{ + dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, + traits::Get, +}; use pallet_evm::GasWeightMapping; use pallet_randomness::{ weights::{SubstrateWeight, WeightInfo}, @@ -38,11 +41,6 @@ mod solidity_types; mod tests; use solidity_types::*; -// Tests to verify equal to weight_to_gas(weight) in runtime integration tests -pub const REQUEST_RANDOMNESS_ESTIMATED_COST: u64 = 26289; -pub const INCREASE_REQUEST_FEE_ESTIMATED_COST: u64 = 16618; -pub const EXECUTE_EXPIRATION_ESTIMATED_COST: u64 = 21830; - /// Fulfillment overhead cost, which takes input weight hint -> weight -> return gas pub fn prepare_and_finish_fulfillment_gas_cost(num_words: u8) -> u64 { ::GasWeightMapping::weight_to_gas( @@ -172,13 +170,17 @@ pub struct RandomnessPrecompile(PhantomData); impl RandomnessPrecompile where Runtime: pallet_randomness::Config + pallet_evm::Config, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + Runtime::RuntimeCall: From>, ::BlockNumber: TryInto + TryFrom, BalanceOf: TryFrom + Into, { #[precompile::public("relayEpochIndex()")] #[precompile::view] fn relay_epoch_index(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let relay_epoch_index = ::BabeDataGetter::get_epoch_index(); Ok(relay_epoch_index) @@ -186,8 +188,7 @@ where #[precompile::public("requiredDeposit()")] #[precompile::view] - fn required_deposit(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + fn required_deposit(_handle: &mut impl PrecompileHandle) -> EvmResult { let required_deposit: U256 = ::Deposit::get().into(); Ok(required_deposit) } @@ -198,13 +199,20 @@ where handle: &mut impl PrecompileHandle, request_id: Convert, ) -> EvmResult { - // record cost of 2 DB reads - handle.record_cost(RuntimeHelper::::db_read_gas_cost() * 2)?; - let request_id = request_id.converted(); + // Storage item read: pallet_randomness::Requests + // Max encoded len: Twox64(8) + RequestId(8) + RequestState( + // request(refund_address(20)+contract_address(20)+fee(16)+gas_limit(8)+num_words(1) + // +salt(32)+info(17)) + // + deposit(16) ) + handle.record_db_read::(146)?; + let status = if let Some(RequestState { request, .. }) = Pallet::::requests(request_id) { + // Storage item read: pallet_randomness::RelayEpoch + // Max encoded len: u64(8) + handle.record_db_read::(8)?; if request.is_expired() { RequestStatus::Expired } else if request.can_be_fulfilled() { @@ -238,14 +246,21 @@ where u64, // expiration epoch index RequestStatus, )> { - // record cost of 2 DB reads - handle.record_cost(RuntimeHelper::::db_read_gas_cost() * 2)?; - let request_id = request_id.converted(); + // Storage item read: pallet_randomness::Requests + // Max encoded len: Twox64(8) + RequestId(8) + RequestState( + // request(refund_address(20)+contract_address(20)+fee(16)+gas_limit(8)+num_words(1) + // +salt(32)+info(17)) + // + deposit(16) ) + handle.record_db_read::(146)?; + let RequestState { request, .. } = Pallet::::requests(request_id).ok_or(revert("Request Does Not Exist"))?; + // Storage item read: pallet_randomness::RelayEpoch + // Max encoded len: u64(8) + handle.record_db_read::(8)?; let status = if request.is_expired() { RequestStatus::Expired } else if request.can_be_fulfilled() { @@ -317,9 +332,8 @@ where salt: H256, num_words: u8, ) -> EvmResult { - handle.record_cost( - REQUEST_RANDOMNESS_ESTIMATED_COST + RuntimeHelper::::db_read_gas_cost(), - )?; + // Until proper benchmark, charge few hardcoded gas to prevent free spam + handle.record_cost(500)?; let refund_address: H160 = refund_address.into(); let fee: BalanceOf = fee @@ -343,11 +357,14 @@ where info: RequestType::BabeEpoch(two_epochs_later), }; - let request_id: U256 = Pallet::::request_randomness(request) - .map_err(|e| revert(alloc::format!("Error in pallet_randomness: {:?}", e)))? - .into(); + let request_randomness_weight = + <::WeightInfo>::request_randomness(); + RuntimeHelper::::record_weight_v2_cost(handle, request_randomness_weight)?; + let request_id = Pallet::::request_randomness(request) + .map_err(|e| revert(alloc::format!("Error in pallet_randomness: {:?}", e)))?; + RuntimeHelper::::refund_weight_v2_cost(handle, request_randomness_weight, None)?; - Ok(request_id) + Ok(request_id.into()) } /// Make request for local VRF randomness #[precompile::public("requestLocalVRFRandomWords(address,uint256,uint64,bytes32,uint8,uint64)")] @@ -360,9 +377,8 @@ where num_words: u8, delay: Convert, ) -> EvmResult { - handle.record_cost( - REQUEST_RANDOMNESS_ESTIMATED_COST + RuntimeHelper::::db_read_gas_cost(), - )?; + // Until proper benchmark, charge few hardcoded gas to prevent free spam + handle.record_cost(500)?; let refund_address: H160 = refund_address.into(); let fee: BalanceOf = fee @@ -392,11 +408,14 @@ where info: RequestType::Local(requested_block_number), }; - let request_id: U256 = Pallet::::request_randomness(request) - .map_err(|e| revert(alloc::format!("Error in pallet_randomness: {:?}", e)))? - .into(); + let request_randomness_weight = + <::WeightInfo>::request_randomness(); + RuntimeHelper::::record_weight_v2_cost(handle, request_randomness_weight)?; + let request_id = Pallet::::request_randomness(request) + .map_err(|e| revert(alloc::format!("Error in pallet_randomness: {:?}", e)))?; + RuntimeHelper::::refund_weight_v2_cost(handle, request_randomness_weight, None)?; - Ok(request_id) + Ok(request_id.into()) } /// Fulfill a randomness request due to be fulfilled @@ -407,45 +426,54 @@ where ) -> EvmResult { let request_id = request_id.converted(); - // Since we cannot compute `prepare_and_finish_fulfillment_cost` now (we don't - // know the number of words), we compute the cost for the maximum allowed number of - // words. - let max_prepare_and_finish_fulfillment_cost = - prepare_and_finish_fulfillment_gas_cost::( - ::MaxRandomWords::get(), + // Call `prepare_fulfillment`, prevently charge for MaxRandomWords then refund. + let prepare_fulfillment_max_weight = + <::WeightInfo>::prepare_fulfillment( + ::MaxRandomWords::get() as u32, ); - - if handle.remaining_gas() < max_prepare_and_finish_fulfillment_cost { - return Err(revert(alloc::format!( - "provided gas must be at least {max_prepare_and_finish_fulfillment_cost}" - ))); - } - + RuntimeHelper::::record_weight_v2_cost(handle, prepare_fulfillment_max_weight)?; let pallet_randomness::FulfillArgs { request, deposit, randomness, } = Pallet::::prepare_fulfillment(request_id) .map_err(|e| revert(alloc::format!("{:?}", e)))?; - - let prepare_and_finish_fulfillment_cost = - prepare_and_finish_fulfillment_gas_cost::(request.num_words); - handle.record_cost(prepare_and_finish_fulfillment_cost)?; + let prepare_fulfillment_actual_weight = + <::WeightInfo>::prepare_fulfillment( + request.num_words as u32, + ); + let mut prepare_and_finish_fulfillment_used_gas = + RuntimeHelper::::refund_weight_v2_cost( + handle, + prepare_fulfillment_max_weight, + Some(prepare_fulfillment_actual_weight), + )?; let subcall_overhead_gas_costs = subcall_overhead_gas_costs::()?; + // Precharge for finish fullfillment (necessary to be able to compute + // prepare_and_finish_fulfillment_used_gas) + let finish_fulfillment_weight = + <::WeightInfo>::finish_fulfillment(); + RuntimeHelper::::record_weight_v2_cost(handle, finish_fulfillment_weight)?; + prepare_and_finish_fulfillment_used_gas += RuntimeHelper::::refund_weight_v2_cost( + handle, + finish_fulfillment_weight, + None, + )?; + // check that randomness can be provided ensure_can_provide_randomness::( handle.remaining_gas(), request.gas_limit, request.fee, subcall_overhead_gas_costs, - prepare_and_finish_fulfillment_cost, + prepare_and_finish_fulfillment_used_gas, )?; // We meter this section to know how much gas was actually used. // It contains the gas used by the subcall and the overhead actually - // performing a call. It doesn't contain `prepare_and_finish_fulfillment_cost`. + // performing a call. It doesn't contain `prepare_and_finish_fulfillment_used_gas`. let remaining_gas_before = handle.remaining_gas(); provide_randomness( handle, @@ -457,11 +485,11 @@ where let remaining_gas_after = handle.remaining_gas(); // We compute the actual gas used to refund the caller. - // It is the metered gas + `prepare_and_finish_fulfillment_cost`. + // It is the metered gas + `prepare_and_finish_fulfillment_used_gas`. let gas_used: U256 = remaining_gas_before .checked_sub(remaining_gas_after) .ok_or(revert("Before remaining gas < After remaining gas"))? - .checked_add(prepare_and_finish_fulfillment_cost) + .checked_add(prepare_and_finish_fulfillment_used_gas) .ok_or(revert("overflow when adding real call cost + overhead"))? .checked_add(transaction_gas_refund::()) .ok_or(revert("overflow when adding real call cost + overhead"))? @@ -495,7 +523,9 @@ where request_id: Convert, fee_increase: U256, ) -> EvmResult { - handle.record_cost(INCREASE_REQUEST_FEE_ESTIMATED_COST)?; + let increase_fee_weight = + <::WeightInfo>::increase_fee(); + RuntimeHelper::::record_weight_v2_cost(handle, increase_fee_weight)?; let request_id = request_id.converted(); @@ -506,6 +536,8 @@ where Pallet::::increase_request_fee(&handle.context().caller, request_id, fee_increase) .map_err(|e| revert(alloc::format!("{:?}", e)))?; + RuntimeHelper::::refund_weight_v2_cost(handle, increase_fee_weight, None)?; + Ok(()) } /// Execute request expiration to remove the request from storage @@ -515,12 +547,20 @@ where handle: &mut impl PrecompileHandle, request_id: Convert, ) -> EvmResult { - handle.record_cost(EXECUTE_EXPIRATION_ESTIMATED_COST)?; + let execute_request_expiration_weight = + <::WeightInfo>::execute_request_expiration(); + RuntimeHelper::::record_weight_v2_cost(handle, execute_request_expiration_weight)?; let request_id = request_id.converted(); Pallet::::execute_request_expiration(&handle.context().caller, request_id) .map_err(|e| revert(alloc::format!("{:?}", e)))?; + RuntimeHelper::::refund_weight_v2_cost( + handle, + execute_request_expiration_weight, + None, + )?; + Ok(()) } } diff --git a/precompiles/randomness/src/mock.rs b/precompiles/randomness/src/mock.rs index 3db6685ea6..3d47ab2f9b 100644 --- a/precompiles/randomness/src/mock.rs +++ b/precompiles/randomness/src/mock.rs @@ -141,6 +141,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = (); + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -192,6 +195,7 @@ impl pallet_randomness::Config for Runtime { type MaxBlockDelay = MaxBlockDelay; type BlockExpirationDelay = MaxBlockDelay; type EpochExpirationDelay = MaxBlockDelay; + type WeightInfo = pallet_randomness::weights::SubstrateWeight; } /// Externality builder for pallet randomness mock runtime diff --git a/precompiles/referenda/src/lib.rs b/precompiles/referenda/src/lib.rs index 45f896ed5a..29b40427f8 100644 --- a/precompiles/referenda/src/lib.rs +++ b/precompiles/referenda/src/lib.rs @@ -26,7 +26,7 @@ use pallet_referenda::{ Call as ReferendaCall, DecidingCount, Deposit, Pallet as Referenda, ReferendumCount, ReferendumInfo, ReferendumInfoFor, TracksInfo, }; -use parity_scale_codec::Encode; +use parity_scale_codec::{Encode, MaxEncodedLen}; use precompile_utils::prelude::*; use sp_core::{H160, H256, U256}; use sp_std::{boxed::Box, marker::PhantomData, str::FromStr, vec::Vec}; @@ -154,8 +154,8 @@ where #[precompile::public("referendumCount()")] #[precompile::view] fn referendum_count(handle: &mut impl PrecompileHandle) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumCount + handle.record_db_read::(4)?; let ref_count = ReferendumCount::::get(); log::trace!(target: "referendum-precompile", "Referendum count is {:?}", ref_count); @@ -164,9 +164,7 @@ where #[precompile::public("submissionDeposit()")] #[precompile::view] - fn submission_deposit(handle: &mut impl PrecompileHandle) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + fn submission_deposit(_handle: &mut impl PrecompileHandle) -> EvmResult { let submission_deposit = Runtime::SubmissionDeposit::get(); log::trace!(target: "referendum-precompile", "Submission deposit is {:?}", submission_deposit); @@ -176,8 +174,9 @@ where #[precompile::public("decidingCount(uint16)")] #[precompile::view] fn deciding_count(handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // DecidingCount: + // Twox64Concat(8) + TrackIdOf(2) + 4 + handle.record_db_read::(14)?; let track_id: TrackIdOf = track_id .try_into() .map_err(|_| RevertReason::value_is_too_large("Track id type").into()) @@ -194,9 +193,7 @@ where #[precompile::public("trackIds()")] #[precompile::view] - fn track_ids(handle: &mut impl PrecompileHandle) -> EvmResult> { - // Fetch data from runtime - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + fn track_ids(_handle: &mut impl PrecompileHandle) -> EvmResult> { let track_ids: Vec = Runtime::Tracks::tracks() .into_iter() .filter_map(|(id, _)| { @@ -213,9 +210,7 @@ where #[precompile::public("trackInfo(uint16)")] #[precompile::view] - fn track_info(handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult { - // Fetch data from runtime - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + fn track_info(_handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult { let track_id: TrackIdOf = track_id .try_into() .map_err(|_| RevertReason::value_is_too_large("Track id type").into()) @@ -273,8 +268,8 @@ where proposal.len(), track_id ); - // for read of referendumCount to get the referendum index - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumCount + handle.record_db_read::(4)?; let referendum_index = ReferendumCount::::get(); let proposal_origin = Self::track_id_to_origin( @@ -303,8 +298,10 @@ where handle: &mut impl PrecompileHandle, referendum_index: u32, ) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; let status = match ReferendumInfoFor::::get(referendum_index).ok_or( RevertReason::custom("Referendum does not exist for index") @@ -327,8 +324,10 @@ where handle: &mut impl PrecompileHandle, referendum_index: u32, ) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; match ReferendumInfoFor::::get(referendum_index).ok_or( RevertReason::custom("Referendum does not exist for index") @@ -396,8 +395,10 @@ where handle: &mut impl PrecompileHandle, referendum_index: u32, ) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; let get_closed_ref_info = |status, @@ -453,8 +454,10 @@ where handle: &mut impl PrecompileHandle, referendum_index: u32, ) -> EvmResult { - // Fetch data from pallet - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; let block = match ReferendumInfoFor::::get(referendum_index).ok_or( RevertReason::custom("Referendum does not exist for index") @@ -550,8 +553,10 @@ where /// * index: The index of the submitted referendum whose Decision Deposit is yet to be posted. #[precompile::public("placeDecisionDeposit(uint32)")] fn place_decision_deposit(handle: &mut impl PrecompileHandle, index: u32) -> EvmResult { - // Account later `ensure_ongoing` read cost - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; handle.record_log_costs_manual(1, 32 * 3)?; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); @@ -591,8 +596,10 @@ where #[precompile::public("refundDecisionDeposit(uint32)")] fn refund_decision_deposit(handle: &mut impl PrecompileHandle, index: u32) -> EvmResult { handle.record_log_costs_manual(1, 32 * 3)?; - // Get refunding deposit before dispatch - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; let (who, refunded_deposit): (H160, U256) = match ReferendumInfoFor::::get(index) .ok_or( RevertReason::custom("Referendum index does not exist").in_field("index"), @@ -627,8 +634,10 @@ where #[precompile::public("refundSubmissionDeposit(uint32)")] fn refund_submission_deposit(handle: &mut impl PrecompileHandle, index: u32) -> EvmResult { handle.record_log_costs_manual(1, 32 * 3)?; - // Get refunding deposit before dispatch - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // ReferendumInfoFor: Blake2128(16) + 4 + ReferendumInfoOf::max_encoded_len + handle.record_db_read::( + 20 + pallet_referenda::ReferendumInfoOf::::max_encoded_len(), + )?; let (who, refunded_deposit): (H160, U256) = match ReferendumInfoFor::::get(index) .ok_or(RevertReason::custom("Referendum index does not exist").in_field("index"))? diff --git a/precompiles/referenda/src/mock.rs b/precompiles/referenda/src/mock.rs index 37131f4607..efa375b767 100644 --- a/precompiles/referenda/src/mock.rs +++ b/precompiles/referenda/src/mock.rs @@ -117,10 +117,16 @@ pub type TestPrecompiles = PrecompileSetBuilder< pub type PCall = ReferendaPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: TestPrecompiles = TestPrecompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -141,6 +147,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/relay-encoder/src/lib.rs b/precompiles/relay-encoder/src/lib.rs index e53b8b65be..79c42594a9 100644 --- a/precompiles/relay-encoder/src/lib.rs +++ b/precompiles/relay-encoder/src/lib.rs @@ -88,7 +88,9 @@ where amount: U256, reward_destination: RewardDestinationWrapper, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let address: [u8; 32] = controller_address.into(); let relay_amount = u256_to_relay_amount(amount)?; @@ -112,7 +114,9 @@ where handle: &mut impl PrecompileHandle, amount: U256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let relay_amount = u256_to_relay_amount(amount)?; let encoded = RelayRuntime::encode_call(AvailableStakeCalls::BondExtra(relay_amount)) @@ -129,7 +133,9 @@ where handle: &mut impl PrecompileHandle, amount: U256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let relay_amount = u256_to_relay_amount(amount)?; @@ -147,7 +153,9 @@ where handle: &mut impl PrecompileHandle, slashes: u32, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::encode_call(AvailableStakeCalls::WithdrawUnbonded(slashes)) .as_slice() @@ -164,7 +172,9 @@ where comission: Convert, blocked: bool, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let fraction = Perbill::from_parts(comission.converted()); let encoded = RelayRuntime::encode_call(AvailableStakeCalls::Validate( @@ -186,7 +196,9 @@ where handle: &mut impl PrecompileHandle, nominees: BoundedVec, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let nominees: Vec<_> = nominees.into(); let nominated: Vec = nominees @@ -207,7 +219,9 @@ where #[precompile::public("encode_chill()")] #[precompile::view] fn encode_chill(handle: &mut impl PrecompileHandle) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::encode_call(AvailableStakeCalls::Chill) .as_slice() @@ -223,7 +237,9 @@ where handle: &mut impl PrecompileHandle, reward_destination: RewardDestinationWrapper, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let reward_destination = reward_destination.into(); @@ -241,7 +257,9 @@ where handle: &mut impl PrecompileHandle, controller: U256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let controller: [u8; 32] = controller.into(); @@ -260,7 +278,9 @@ where handle: &mut impl PrecompileHandle, amount: U256, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let relay_amount = u256_to_relay_amount(amount)?; let encoded = RelayRuntime::encode_call(AvailableStakeCalls::Rebond(relay_amount)) @@ -278,7 +298,9 @@ where max_capacity: u32, max_message_size: u32, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::hrmp_encode_call(HrmpAvailableCalls::InitOpenChannel( recipient.into(), @@ -301,7 +323,9 @@ where handle: &mut impl PrecompileHandle, sender: u32, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::hrmp_encode_call(HrmpAvailableCalls::AcceptOpenChannel(sender.into())) @@ -322,7 +346,9 @@ where sender: u32, recipient: u32, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::hrmp_encode_call(HrmpAvailableCalls::CloseChannel( relay_chain::HrmpChannelId { @@ -348,7 +374,9 @@ where recipient: u32, open_requests: u32, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // No DB access but lot of logical stuff + // To prevent spam, we charge an arbitrary amount of gas + handle.record_cost(1000)?; let encoded = RelayRuntime::hrmp_encode_call(HrmpAvailableCalls::CancelOpenRequest( relay_chain::HrmpChannelId { diff --git a/precompiles/relay-encoder/src/mock.rs b/precompiles/relay-encoder/src/mock.rs index 7fcdce4f48..50375205ea 100644 --- a/precompiles/relay-encoder/src/mock.rs +++ b/precompiles/relay-encoder/src/mock.rs @@ -117,10 +117,16 @@ pub type Precompiles = PrecompileSetBuilder< pub type PCall = RelayEncoderPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -141,6 +147,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/relay-encoder/src/tests.rs b/precompiles/relay-encoder/src/tests.rs index ee769392d6..319dc35eb7 100644 --- a/precompiles/relay-encoder/src/tests.rs +++ b/precompiles/relay-encoder/src/tests.rs @@ -95,7 +95,7 @@ fn test_encode_bond() { reward_destination: RewardDestinationWrapper(RewardDestination::Controller), }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Bond( @@ -120,7 +120,7 @@ fn test_encode_bond_more() { Precompile1, PCall::encode_bond_extra { amount: 100.into() }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::BondExtra(100u32.into())) @@ -137,7 +137,7 @@ fn test_encode_chill() { .execute_with(|| { precompiles() .prepare_test(Alice, Precompile1, PCall::encode_chill {}) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Chill).as_slice(), @@ -159,7 +159,7 @@ fn test_encode_nominate() { nominees: vec![U256::from([1u8; 32]), U256::from([2u8; 32])].into(), }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Nominate(vec![ @@ -183,7 +183,7 @@ fn test_encode_rebond() { Precompile1, PCall::encode_rebond { amount: 100.into() }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Rebond(100u128)).as_slice(), @@ -205,7 +205,7 @@ fn test_encode_set_controller() { controller: [1u8; 32].into(), }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::SetController([1u8; 32].into())) @@ -228,7 +228,7 @@ fn test_encode_set_payee() { reward_destination: RewardDestinationWrapper(RewardDestination::Controller), }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::SetPayee( @@ -251,7 +251,7 @@ fn test_encode_unbond() { Precompile1, PCall::encode_unbond { amount: 100.into() }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Unbond(100u32.into())).as_slice(), @@ -274,7 +274,7 @@ fn test_encode_validate() { blocked: true, }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::Validate(ValidatorPrefs { @@ -298,7 +298,7 @@ fn test_encode_withdraw_unbonded() { Precompile1, PCall::encode_withdraw_unbonded { slashes: 100 }, ) - .expect_cost(0) // TODO: Test db read/write costs + .expect_cost(1000) .expect_no_logs() .execute_returns(UnboundedBytes::from( TestEncoder::encode_call(AvailableStakeCalls::WithdrawUnbonded(100u32.into())) diff --git a/precompiles/utils/src/evm/handle.rs b/precompiles/utils/src/evm/handle.rs index a468fa9af3..2ae7c77282 100644 --- a/precompiles/utils/src/evm/handle.rs +++ b/precompiles/utils/src/evm/handle.rs @@ -27,6 +27,14 @@ use { }; pub trait PrecompileHandleExt: PrecompileHandle { + /// Record cost of one DB read manually. + /// The max encoded lenght of the data that will be read should be provided. + #[must_use] + fn record_db_read( + &mut self, + data_max_encoded_len: usize, + ) -> Result<(), evm::ExitError>; + /// Record cost of a log manually. /// This can be useful to record log costs early when their content have static size. #[must_use] @@ -51,6 +59,16 @@ pub trait PrecompileHandleExt: PrecompileHandle { } impl PrecompileHandleExt for T { + #[must_use] + fn record_db_read( + &mut self, + data_max_encoded_len: usize, + ) -> Result<(), evm::ExitError> { + self.record_cost(crate::prelude::RuntimeHelper::::db_read_gas_cost())?; + // TODO: record ref time when precompile will be benchmarked + self.record_external_cost(None, Some(data_max_encoded_len as u64)) + } + /// Record cost of a log manualy. /// This can be useful to record log costs early when their content have static size. #[must_use] @@ -178,6 +196,16 @@ mod tests { fn gas_limit(&self) -> Option { unimplemented!() } + + fn record_external_cost( + &mut self, + _ref_time: Option, + _proof_size: Option, + ) -> Result<(), fp_evm::ExitError> { + Ok(()) + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} } #[test] diff --git a/precompiles/utils/src/precompile_set.rs b/precompiles/utils/src/precompile_set.rs index f84eb862ca..8be669151e 100644 --- a/precompiles/utils/src/precompile_set.rs +++ b/precompiles/utils/src/precompile_set.rs @@ -19,8 +19,8 @@ //! default and must be disabled explicely throught type annotations. use crate::{ + evm::handle::PrecompileHandleExt, solidity::{codec::String, revert::revert}, - substrate::RuntimeHelper, EvmResult, }; use fp_evm::{ @@ -314,32 +314,42 @@ pub enum AddressType { } /// Retrieves the type of address demarcated by `AddressType`. -pub fn get_address_type(address: H160) -> AddressType { - let code_len = pallet_evm::AccountCodes::::decode_len(address).unwrap_or(0); +pub fn get_address_type( + handle: &mut impl PrecompileHandle, + address: H160, +) -> Result { + // AccountCodesMetadata: + // Blake2128(16) + H160(20) + CodeMetadata(40) + handle.record_db_read::(76)?; + let code_len = pallet_evm::Pallet::::account_code_metadata(address).size; // 0 => either EOA or precompile without dummy code if code_len == 0 { - return AddressType::EOA; + return Ok(AddressType::EOA); } // dummy code is 5 bytes long, so any other len means it is a contract. if code_len != 5 { - return AddressType::Contract; + return Ok(AddressType::Contract); } // check code matches dummy code + handle.record_db_read::(code_len as usize)?; let code = pallet_evm::AccountCodes::::get(address); if &code == &[0x60, 0x00, 0x60, 0x00, 0xfd] { - return AddressType::Precompile; + return Ok(AddressType::Precompile); } - AddressType::Unknown + Ok(AddressType::Unknown) } -fn is_address_eoa_or_precompile(address: H160) -> bool { - match get_address_type::(address) { - AddressType::EOA | AddressType::Precompile => true, - _ => false, +fn is_address_eoa_or_precompile( + handle: &mut impl PrecompileHandle, + address: H160, +) -> Result { + match get_address_type::(handle, address)? { + AddressType::EOA | AddressType::Precompile => Ok(true), + _ => Ok(false), } } @@ -368,8 +378,7 @@ fn common_checks( let callable_by_smart_contract = C::callable_by_smart_contract(caller, selector).unwrap_or(false); if !callable_by_smart_contract { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; - if !is_address_eoa_or_precompile::(caller) { + if !is_address_eoa_or_precompile::(handle, caller)? { return Err(revert("Function not callable by smart contracts")); } } @@ -462,6 +471,18 @@ impl<'a, H: PrecompileHandle> PrecompileHandle for RestrictiveHandle<'a, H> { fn gas_limit(&self) -> Option { self.handle.gas_limit() } + + fn record_external_cost( + &mut self, + ref_time: Option, + proof_size: Option, + ) -> Result<(), ExitError> { + self.handle.record_external_cost(ref_time, proof_size) + } + + fn refund_external_cost(&mut self, ref_time: Option, proof_size: Option) { + self.handle.refund_external_cost(ref_time, proof_size) + } } /// Allows to know if a precompile is active or not. diff --git a/precompiles/utils/src/substrate.rs b/precompiles/utils/src/substrate.rs index c0b88bb739..1f03f428a0 100644 --- a/precompiles/utils/src/substrate.rs +++ b/precompiles/utils/src/substrate.rs @@ -24,7 +24,7 @@ use { fp_evm::{ExitError, PrecompileFailure, PrecompileHandle}, frame_support::{ dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, - pallet_prelude::DispatchError, + pallet_prelude::*, traits::Get, }, pallet_evm::GasWeightMapping, @@ -57,6 +57,43 @@ where Runtime: pallet_evm::Config, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, { + #[inline(always)] + pub fn record_weight_v2_cost( + handle: &mut impl PrecompileHandle, + weight: Weight, + ) -> Result<(), ExitError> { + // Make sure there is enough gas. + let remaining_gas = handle.remaining_gas(); + let required_gas = Runtime::GasWeightMapping::weight_to_gas(weight); + if required_gas > remaining_gas { + return Err(ExitError::OutOfGas); + } + + // Make sure there is enough remaining weight + // TODO: record ref time when precompile will be benchmarked + handle.record_external_cost(None, Some(weight.proof_size())) + } + + #[inline(always)] + pub fn refund_weight_v2_cost( + handle: &mut impl PrecompileHandle, + weight: Weight, + maybe_actual_weight: Option, + ) -> Result { + // Refund weights and compute used weight them record used gas + // TODO: refund ref time when precompile will be benchmarked + let used_weight = if let Some(actual_weight) = maybe_actual_weight { + let refund_weight = weight - actual_weight; + handle.refund_external_cost(None, Some(refund_weight.proof_size())); + actual_weight + } else { + weight + }; + let used_gas = Runtime::GasWeightMapping::weight_to_gas(used_weight); + handle.record_cost(used_gas)?; + Ok(used_gas) + } + /// Try to dispatch a Substrate call. /// Return an error if there are not enough gas, or if the call fails. /// If successful returns the used gas using the Runtime GasWeightMapping. @@ -71,12 +108,8 @@ where let call = Runtime::RuntimeCall::from(call); let dispatch_info = call.get_dispatch_info(); - // Make sure there is enough gas. - let remaining_gas = handle.remaining_gas(); - let required_gas = Runtime::GasWeightMapping::weight_to_gas(dispatch_info.weight); - if required_gas > remaining_gas { - return Err(TryDispatchError::Evm(ExitError::OutOfGas)); - } + Self::record_weight_v2_cost(handle, dispatch_info.weight) + .map_err(|e| TryDispatchError::Evm(e))?; // Dispatch call. // It may be possible to not record gas cost if the call returns Pays::No. @@ -86,14 +119,12 @@ where let post_dispatch_info = using_precompile_handle(handle, || call.dispatch(origin)) .map_err(|e| TryDispatchError::Substrate(e.error))?; - let used_weight = post_dispatch_info.actual_weight; - - let used_gas = - Runtime::GasWeightMapping::weight_to_gas(used_weight.unwrap_or(dispatch_info.weight)); - - handle - .record_cost(used_gas) - .map_err(|e| TryDispatchError::Evm(e))?; + Self::refund_weight_v2_cost( + handle, + dispatch_info.weight, + post_dispatch_info.actual_weight, + ) + .map_err(|e| TryDispatchError::Evm(e))?; Ok(post_dispatch_info) } diff --git a/precompiles/utils/src/testing/handle.rs b/precompiles/utils/src/testing/handle.rs index d97ce9d128..4529141033 100644 --- a/precompiles/utils/src/testing/handle.rs +++ b/precompiles/utils/src/testing/handle.rs @@ -202,4 +202,14 @@ impl PrecompileHandle for MockHandle { fn gas_limit(&self) -> Option { Some(self.gas_limit) } + + fn record_external_cost( + &mut self, + _ref_time: Option, + _proof_size: Option, + ) -> Result<(), ExitError> { + Ok(()) + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} } diff --git a/precompiles/utils/tests-external/lib.rs b/precompiles/utils/tests-external/lib.rs index 30d34135cf..c9ec7a2a0e 100644 --- a/precompiles/utils/tests-external/lib.rs +++ b/precompiles/utils/tests-external/lib.rs @@ -143,6 +143,68 @@ mod tests { } } + struct MockPrecompileHandle; + impl PrecompileHandle for MockPrecompileHandle { + fn call( + &mut self, + _: sp_core::H160, + _: Option, + _: Vec, + _: Option, + _: bool, + _: &evm::Context, + ) -> (evm::ExitReason, Vec) { + unimplemented!() + } + + fn record_cost(&mut self, _: u64) -> Result<(), evm::ExitError> { + Ok(()) + } + + fn remaining_gas(&self) -> u64 { + unimplemented!() + } + + fn log( + &mut self, + _: sp_core::H160, + _: Vec, + _: Vec, + ) -> Result<(), evm::ExitError> { + unimplemented!() + } + + fn code_address(&self) -> sp_core::H160 { + unimplemented!() + } + + fn input(&self) -> &[u8] { + unimplemented!() + } + + fn context(&self) -> &evm::Context { + unimplemented!() + } + + fn is_static(&self) -> bool { + true + } + + fn gas_limit(&self) -> Option { + unimplemented!() + } + + fn record_external_cost( + &mut self, + _ref_time: Option, + _proof_size: Option, + ) -> Result<(), fp_evm::ExitError> { + Ok(()) + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} + } + pub type Precompiles = PrecompileSetBuilder< R, ( @@ -155,10 +217,16 @@ mod tests { pub type PCall = MockPrecompileCall; + const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -179,6 +247,9 @@ mod tests { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -319,7 +390,10 @@ mod tests { fn get_address_type_works_for_eoa() { ExtBuilder::default().build().execute_with(|| { let addr = H160::repeat_byte(0x1d); - assert_eq!(AddressType::EOA, get_address_type::(addr)); + assert_eq!( + AddressType::EOA, + get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") + ); }) } @@ -328,7 +402,10 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let addr = H160::repeat_byte(0x1d); pallet_evm::AccountCodes::::insert(addr, vec![0x60, 0x00, 0x60, 0x00, 0xfd]); - assert_eq!(AddressType::Precompile, get_address_type::(addr)); + assert_eq!( + AddressType::Precompile, + get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") + ); }) } @@ -342,11 +419,17 @@ mod tests { addr, vec![0x60, 0x00, 0x60, 0x00, 0xfd, 0xff, 0xff], ); - assert_eq!(AddressType::Contract, get_address_type::(addr)); + assert_eq!( + AddressType::Contract, + get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") + ); // length < 5 pallet_evm::AccountCodes::::insert(addr, vec![0x60, 0x00, 0x60]); - assert_eq!(AddressType::Contract, get_address_type::(addr)); + assert_eq!( + AddressType::Contract, + get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") + ); }) } @@ -355,7 +438,10 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let addr = H160::repeat_byte(0x1d); pallet_evm::AccountCodes::::insert(addr, vec![0x11, 0x00, 0x60, 0x00, 0xfd]); - assert_eq!(AddressType::Unknown, get_address_type::(addr)); + assert_eq!( + AddressType::Unknown, + get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") + ); }) } } diff --git a/precompiles/xcm-transactor/src/functions.rs b/precompiles/xcm-transactor/src/functions.rs index 72e97a759e..1ff762dd3a 100644 --- a/precompiles/xcm-transactor/src/functions.rs +++ b/precompiles/xcm-transactor/src/functions.rs @@ -26,7 +26,7 @@ use pallet_xcm_transactor::{ Currency, CurrencyPayment, RemoteTransactInfoWithMaxWeight, TransactWeights, }; use precompile_utils::prelude::*; -use sp_core::{H160, U256}; +use sp_core::{MaxEncodedLen, H160, U256}; use sp_std::{ boxed::Box, convert::{TryFrom, TryInto}, @@ -61,7 +61,8 @@ where handle: &mut impl PrecompileHandle, index: u16, ) -> EvmResult
{ - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: IndexToAccount: Blake2_128(16) + u16(2) + AccountId(20) + handle.record_db_read::(38)?; // fetch data from pallet let account: H160 = pallet_xcm_transactor::Pallet::::index_to_account(index) @@ -75,14 +76,20 @@ where handle: &mut impl PrecompileHandle, multilocation: MultiLocation, ) -> EvmResult<(u64, U256, u64)> { - handle.record_cost(2 * RuntimeHelper::::db_read_gas_cost())?; - // fetch data from pallet + // storage item: TransactInfoWithWeightLimit: Blake2_128(16) + MultiLocation + // + RemoteTransactInfoWithMaxWeight + handle.record_db_read::( + 16 + MultiLocation::max_encoded_len() + + RemoteTransactInfoWithMaxWeight::max_encoded_len(), + )?; let remote_transact_info: RemoteTransactInfoWithMaxWeight = pallet_xcm_transactor::Pallet::::transact_info(&multilocation) .ok_or(revert("Transact Info not set"))?; // fetch data from pallet + // storage item: AssetTypeUnitsPerSecond: Blake2_128(16) + MultiLocation + u128(16) + handle.record_db_read::(32 + MultiLocation::max_encoded_len())?; let fee_per_second: u128 = pallet_xcm_transactor::Pallet::::dest_asset_fee_per_second(&multilocation) .ok_or(revert("Fee Per Second not set"))?; @@ -98,9 +105,13 @@ where handle: &mut impl PrecompileHandle, multilocation: MultiLocation, ) -> EvmResult<(u64, u64, u64)> { - handle.record_cost(1 * RuntimeHelper::::db_read_gas_cost())?; - // fetch data from pallet + // storage item: TransactInfoWithWeightLimit: Blake2_128(16) + MultiLocation + // + RemoteTransactInfoWithMaxWeight + handle.record_db_read::( + 16 + MultiLocation::max_encoded_len() + + RemoteTransactInfoWithMaxWeight::max_encoded_len(), + )?; let remote_transact_info: RemoteTransactInfoWithMaxWeight = pallet_xcm_transactor::Pallet::::transact_info(multilocation) .ok_or(revert("Transact Info not set"))?; @@ -120,9 +131,9 @@ where handle: &mut impl PrecompileHandle, multilocation: MultiLocation, ) -> EvmResult { - handle.record_cost(1 * RuntimeHelper::::db_read_gas_cost())?; - // fetch data from pallet + // storage item: AssetTypeUnitsPerSecond: Blake2_128(16) + MultiLocation + u128(16) + handle.record_db_read::(32 + MultiLocation::max_encoded_len())?; let fee_per_second: u128 = pallet_xcm_transactor::Pallet::::dest_asset_fee_per_second(multilocation) .ok_or(revert("Fee Per Second not set"))?; @@ -225,6 +236,10 @@ where weight: u64, inner_call: BoundedBytes, ) -> EvmResult { + // No DB access before try_dispatch but lot of logical stuff + // To prevent spam, we charge an arbitrary amoun of gas + handle.record_cost(1000)?; + let transactor = transactor .try_into() .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?; @@ -233,8 +248,6 @@ where let to_account = Runtime::AddressMapping::into_account_id(currency_id.0); // We convert the address into a currency - // This involves a DB read in moonbeam, hence the db Read - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let currency_id: ::CurrencyId = Runtime::account_to_currency_id(to_account) .ok_or(revert("cannot convert into currency id"))?; @@ -274,6 +287,10 @@ where fee_amount: u128, overall_weight: u64, ) -> EvmResult { + // No DB access before try_dispatch but lot of logical stuff + // To prevent spam, we charge an arbitrary amoun of gas + handle.record_cost(1000)?; + let transactor = transactor .try_into() .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?; @@ -283,8 +300,6 @@ where let to_account = Runtime::AddressMapping::into_account_id(to_address); // We convert the address into a currency - // This involves a DB read in moonbeam, hence the db Read - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let currency_id: ::CurrencyId = Runtime::account_to_currency_id(to_account) .ok_or(revert("cannot convert into currency id"))?; @@ -393,14 +408,16 @@ where weight: u64, call: BoundedBytes, ) -> EvmResult { + // No DB access before try_dispatch but lot of logical stuff + // To prevent spam, we charge an arbitrary amoun of gas + handle.record_cost(1000)?; + let to_address: H160 = fee_asset.into(); let to_account = Runtime::AddressMapping::into_account_id(to_address); let call: Vec<_> = call.into(); // We convert the address into a currency - // This involves a DB read in moonbeam, hence the db Read - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let currency_id: ::CurrencyId = Runtime::account_to_currency_id(to_account) .ok_or(revert("cannot convert into currency id"))?; @@ -438,14 +455,16 @@ where fee_amount: u128, overall_weight: u64, ) -> EvmResult { + // No DB access before try_dispatch but lot of logical stuff + // To prevent spam, we charge an arbitrary amoun of gas + handle.record_cost(1000)?; + let to_address: H160 = fee_asset.into(); let to_account = Runtime::AddressMapping::into_account_id(to_address); let call: Vec<_> = call.into(); // We convert the address into a currency - // This involves a DB read in moonbeam, hence the db Read - handle.record_cost(1 * RuntimeHelper::::db_read_gas_cost())?; let currency_id: ::CurrencyId = Runtime::account_to_currency_id(to_account) .ok_or(revert("cannot convert into currency id"))?; @@ -480,7 +499,10 @@ where index: u16, inner_call: BoundedBytes, ) -> EvmResult { - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // There is no DB read in this function, + // we just account an arbitrary amount of gas to prevent spam + // TODO replace by proper benchmarks + handle.record_cost(1000)?; let transactor: TransactorOf = transactor .try_into() diff --git a/precompiles/xcm-transactor/src/mock.rs b/precompiles/xcm-transactor/src/mock.rs index c3ea2ac026..5a57112893 100644 --- a/precompiles/xcm-transactor/src/mock.rs +++ b/precompiles/xcm-transactor/src/mock.rs @@ -160,10 +160,16 @@ mock_account!(AssetAddress(u128), |value: AssetAddress| { pub type PCallV1 = XcmTransactorPrecompileV1Call; pub type PCallV2 = XcmTransactorPrecompileV2Call; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } /// A mapping function that converts Ethereum gas to Substrate weight @@ -196,6 +202,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/xcm-transactor/src/tests.rs b/precompiles/xcm-transactor/src/tests.rs index 0c1272b72e..c6b4825078 100644 --- a/precompiles/xcm-transactor/src/tests.rs +++ b/precompiles/xcm-transactor/src/tests.rs @@ -369,7 +369,7 @@ fn test_transact_derivative() { inner_call: bytes.into(), }, ) - .expect_cost(188253001) + .expect_cost(188254000) .expect_no_logs() .execute_returns(()); }); @@ -407,7 +407,7 @@ fn test_transact_derivative_v2() { overall_weight: total_weight, }, ) - .expect_cost(188253001) + .expect_cost(188254000) .expect_no_logs() .execute_returns(()); }); @@ -452,7 +452,7 @@ fn test_transact_signed() { call: bytes.into(), }, ) - .expect_cost(468448001) + .expect_cost(468449000) .expect_no_logs() .execute_returns(()); }); @@ -485,7 +485,7 @@ fn test_transact_signed_v2() { overall_weight: total_weight, }, ) - .expect_cost(468448001) + .expect_cost(468449000) .expect_no_logs() .execute_returns(()); }); diff --git a/precompiles/xcm-utils/src/lib.rs b/precompiles/xcm-utils/src/lib.rs index fbb96e7232..732966ac16 100644 --- a/precompiles/xcm-utils/src/lib.rs +++ b/precompiles/xcm-utils/src/lib.rs @@ -26,7 +26,7 @@ use frame_support::{ traits::OriginTrait, }; use pallet_evm::AddressMapping; -use parity_scale_codec::DecodeLimit; +use parity_scale_codec::{DecodeLimit, MaxEncodedLen}; use precompile_utils::precompile_set::SelectorFilter; use precompile_utils::prelude::*; use sp_core::{H160, U256}; @@ -106,9 +106,9 @@ where handle: &mut impl PrecompileHandle, multilocation: MultiLocation, ) -> EvmResult
{ - // TODO: Change once precompiles are benchmarked - // for now we charge a db read, - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: AssetTypeUnitsPerSecond + // max encoded len: hash (16) + Multilocation + u128 (16) + handle.record_db_read::(32 + MultiLocation::max_encoded_len())?; let origin = XcmConfig::OriginConverter::convert_origin(multilocation, OriginKind::SovereignAccount) @@ -132,9 +132,9 @@ where handle: &mut impl PrecompileHandle, multilocation: MultiLocation, ) -> EvmResult { - // TODO: Change once precompiles are benchmarked - // for now we charge a db read, - handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + // storage item: AssetTypeUnitsPerSecond + // max encoded len: hash (16) + Multilocation + u128 (16) + handle.record_db_read::(32 + MultiLocation::max_encoded_len())?; // We will construct an asset with the max amount, and check how much we // get in return to substract diff --git a/precompiles/xcm-utils/src/mock.rs b/precompiles/xcm-utils/src/mock.rs index ad70931d99..441087ecd9 100644 --- a/precompiles/xcm-utils/src/mock.rs +++ b/precompiles/xcm-utils/src/mock.rs @@ -258,10 +258,16 @@ pub type Precompiles = PrecompileSetBuilder< pub type PCall = XcmUtilsPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } /// A mapping function that converts Ethereum gas to Substrate weight @@ -294,6 +300,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/precompiles/xtokens/src/mock.rs b/precompiles/xtokens/src/mock.rs index 7eaeae1401..f763c7736f 100644 --- a/precompiles/xtokens/src/mock.rs +++ b/precompiles/xtokens/src/mock.rs @@ -133,10 +133,16 @@ pub type Precompiles = pub type PCall = XtokensPrecompileCall; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub PrecompilesValue: Precompiles = Precompiles::new(); pub const WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -157,6 +163,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { diff --git a/runtime/common/src/apis.rs b/runtime/common/src/apis.rs index c4d1916d91..4a923b97b6 100644 --- a/runtime/common/src/apis.rs +++ b/runtime/common/src/apis.rs @@ -228,7 +228,7 @@ macro_rules! impl_runtime_apis_plus_common { } fn account_code_at(address: H160) -> Vec { - EVM::account_codes(address) + pallet_evm::AccountCodes::::get(address) } fn author() -> H160 { @@ -238,7 +238,7 @@ macro_rules! impl_runtime_apis_plus_common { fn storage_at(address: H160, index: U256) -> H256 { let mut tmp = [0u8; 32]; index.to_big_endian(&mut tmp); - EVM::account_storages(address, H256::from_slice(&tmp[..])) + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) } fn call( @@ -262,18 +262,55 @@ macro_rules! impl_runtime_apis_plus_common { }; let is_transactional = false; let validate = true; + + let mut estimated_transaction_len = data.len() + + // to: 20 + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 210; + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = 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.low_u64(), + 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()) } @@ -298,32 +335,73 @@ macro_rules! impl_runtime_apis_plus_common { }; let is_transactional = false; let validate = true; + + let mut estimated_transaction_len = data.len() + + // to: 20 + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 210; + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + gas_limit.low_u64() + }; + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + #[allow(clippy::or_fun_call)] // suggestion not helpful here ::Runner::create( from, data, value, - gas_limit.low_u64(), + 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> { - Ethereum::current_transaction_statuses() + pallet_ethereum::CurrentTransactionStatuses::::get() } fn current_block() -> Option { - Ethereum::current_block() + pallet_ethereum::CurrentBlock::::get() } fn current_receipts() -> Option> { - Ethereum::current_receipts() + pallet_ethereum::CurrentReceipts::::get() } fn current_all() -> ( @@ -332,9 +410,9 @@ macro_rules! impl_runtime_apis_plus_common { Option>, ) { ( - Ethereum::current_block(), - Ethereum::current_receipts(), - Ethereum::current_transaction_statuses(), + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get(), ) } diff --git a/runtime/common/src/impl_xcm_evm_runner.rs b/runtime/common/src/impl_xcm_evm_runner.rs index a31657f550..0972bcf59a 100644 --- a/runtime/common/src/impl_xcm_evm_runner.rs +++ b/runtime/common/src/impl_xcm_evm_runner.rs @@ -51,6 +51,8 @@ macro_rules! impl_evm_runner_precompile_or_eth_xcm { access_list: Vec<(H160, Vec)>, _is_transactional: bool, _validate: bool, + _weight_limit: Option, + _transaction_len: Option, _config: &fp_evm::Config, ) -> Result> { // The `with_precompile_handle` function will execute the closure (and return the @@ -83,8 +85,12 @@ macro_rules! impl_evm_runner_precompile_or_eth_xcm { Ok(CallInfo { exit_reason, value, - used_gas: U256::default(), + used_gas: fp_evm::UsedGas { + standard: U256::default(), + effective: U256::default(), + }, logs: Default::default(), + weight_info: None, }) } else { let xcm_transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { @@ -133,6 +139,8 @@ macro_rules! impl_evm_runner_precompile_or_eth_xcm { _access_list: Vec<(H160, Vec)>, _is_transactional: bool, _validate: bool, + _weight_limit: Option, + _transaction_len: Option, _config: &fp_evm::Config, ) -> Result> { unimplemented!() @@ -150,6 +158,8 @@ macro_rules! impl_evm_runner_precompile_or_eth_xcm { _access_list: Vec<(H160, Vec)>, _is_transactional: bool, _validate: bool, + _weight_limit: Option, + _transaction_len: Option, _config: &fp_evm::Config, ) -> Result> { unimplemented!() @@ -166,6 +176,8 @@ macro_rules! impl_evm_runner_precompile_or_eth_xcm { _nonce: Option, _access_list: Vec<(H160, Vec)>, _is_transactional: bool, + _weight_limit: Option, + _transaction_len: Option, _evm_config: &fp_evm::Config, ) -> Result<(), RunnerError> { unimplemented!() diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index 82c49b0281..fd2dce99f2 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -404,6 +404,12 @@ parameter_types! { pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); pub PrecompilesValue: MoonbasePrecompiles = MoonbasePrecompiles::<_>::new(); pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + pub const GasLimitPovSizeRatio: u64 = 4; } pub struct TransactionPaymentAsGasPrice; @@ -487,6 +493,9 @@ impl pallet_evm::Config for Runtime { type BlockGasLimit = BlockGasLimit; type FindAuthor = FindAuthorAdapter; type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -618,6 +627,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } pub struct EthereumXcmEnsureProxy; @@ -1262,6 +1272,7 @@ impl pallet_randomness::Config for Runtime { type MaxBlockDelay = ConstU32<2_000>; type BlockExpirationDelay = ConstU32<10_000>; type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = pallet_randomness::weights::SubstrateWeight; } impl pallet_root_testing::Config for Runtime {} diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index 7e456d0809..fa37e05873 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -56,16 +56,10 @@ use xcm_executor::traits::Convert as XcmConvert; use moonbeam_xcm_benchmarks::weights::XcmWeight; use nimbus_primitives::NimbusId; -use pallet_evm::GasWeightMapping; use pallet_evm::PrecompileSet; -use pallet_evm_precompile_randomness::{ - EXECUTE_EXPIRATION_ESTIMATED_COST, INCREASE_REQUEST_FEE_ESTIMATED_COST, - REQUEST_RANDOMNESS_ESTIMATED_COST, -}; use pallet_evm_precompileset_assets_erc20::{ AccountIdAssetIdConversion, IsLocal, SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER, }; -use pallet_randomness::weights::{SubstrateWeight, WeightInfo}; use pallet_transaction_payment::Multiplier; use pallet_xcm_transactor::{Currency, CurrencyPayment, HrmpOperation, TransactWeights}; use parity_scale_codec::Encode; @@ -97,26 +91,6 @@ type XcmTransactorV2PCall = // TODO: can we construct a const U256...? const BASE_FEE_GENISIS: u128 = 10 * GIGAWEI; -#[test] -fn verify_randomness_precompile_gas_constants() { - let weight_to_gas = |weight| { - ::GasWeightMapping::weight_to_gas(weight) - }; - type Weight = SubstrateWeight; - assert_eq!( - weight_to_gas(Weight::request_randomness()), - REQUEST_RANDOMNESS_ESTIMATED_COST - ); - assert_eq!( - weight_to_gas(Weight::increase_fee()), - INCREASE_REQUEST_FEE_ESTIMATED_COST - ); - assert_eq!( - weight_to_gas(Weight::execute_request_expiration()), - EXECUTE_EXPIRATION_ESTIMATED_COST - ); -} - #[test] fn xcmp_queue_controller_origin_is_root() { // important for the XcmExecutionManager impl of PauseExecution which uses root origin diff --git a/runtime/moonbase/tests/xcm_mock/parachain.rs b/runtime/moonbase/tests/xcm_mock/parachain.rs index 68204b3acd..724ca93c3c 100644 --- a/runtime/moonbase/tests/xcm_mock/parachain.rs +++ b/runtime/moonbase/tests/xcm_mock/parachain.rs @@ -916,9 +916,15 @@ impl pallet_timestamp::Config for Runtime { use sp_core::U256; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -942,6 +948,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } pub struct NormalFilter; @@ -1042,6 +1051,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } parameter_types! { pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); diff --git a/runtime/moonbeam/src/lib.rs b/runtime/moonbeam/src/lib.rs index a596b8ee41..5f40a30ac3 100644 --- a/runtime/moonbeam/src/lib.rs +++ b/runtime/moonbeam/src/lib.rs @@ -391,6 +391,12 @@ parameter_types! { pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); pub PrecompilesValue: MoonbeamPrecompiles = MoonbeamPrecompiles::<_>::new(); pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + pub const GasLimitPovSizeRatio: u64 = 4; } pub struct TransactionPaymentAsGasPrice; @@ -477,6 +483,9 @@ impl pallet_evm::Config for Runtime { type BlockGasLimit = BlockGasLimit; type FindAuthor = FindAuthorAdapter; type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -607,6 +616,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } impl cumulus_pallet_parachain_system::Config for Runtime { @@ -1272,6 +1282,7 @@ impl pallet_randomness::Config for Runtime { type MaxBlockDelay = ConstU32<2_000>; type BlockExpirationDelay = ConstU32<10_000>; type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = pallet_randomness::weights::SubstrateWeight; } impl pallet_root_testing::Config for Runtime {} diff --git a/runtime/moonbeam/tests/xcm_mock/parachain.rs b/runtime/moonbeam/tests/xcm_mock/parachain.rs index edaea851b5..f760147049 100644 --- a/runtime/moonbeam/tests/xcm_mock/parachain.rs +++ b/runtime/moonbeam/tests/xcm_mock/parachain.rs @@ -897,9 +897,15 @@ impl pallet_timestamp::Config for Runtime { use sp_core::U256; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -923,6 +929,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } pub struct NormalFilter; @@ -1023,6 +1032,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } parameter_types! { diff --git a/runtime/moonriver/src/lib.rs b/runtime/moonriver/src/lib.rs index fe08d9b083..50a5a35e27 100644 --- a/runtime/moonriver/src/lib.rs +++ b/runtime/moonriver/src/lib.rs @@ -392,6 +392,12 @@ parameter_types! { pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); pub PrecompilesValue: MoonriverPrecompiles = MoonriverPrecompiles::<_>::new(); pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + pub const GasLimitPovSizeRatio: u64 = 4; } pub struct TransactionPaymentAsGasPrice; @@ -478,6 +484,9 @@ impl pallet_evm::Config for Runtime { type BlockGasLimit = BlockGasLimit; type FindAuthor = FindAuthorAdapter; type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } parameter_types! { @@ -608,6 +617,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } pub struct EthereumXcmEnsureProxy; @@ -1281,6 +1291,7 @@ impl pallet_randomness::Config for Runtime { type MaxBlockDelay = ConstU32<2_000>; type BlockExpirationDelay = ConstU32<10_000>; type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = pallet_randomness::weights::SubstrateWeight; } impl pallet_root_testing::Config for Runtime {} diff --git a/runtime/moonriver/tests/xcm_mock/parachain.rs b/runtime/moonriver/tests/xcm_mock/parachain.rs index 9b3480a448..0683728f4c 100644 --- a/runtime/moonriver/tests/xcm_mock/parachain.rs +++ b/runtime/moonriver/tests/xcm_mock/parachain.rs @@ -907,9 +907,15 @@ impl pallet_timestamp::Config for Runtime { use sp_core::U256; +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; + parameter_types! { - pub BlockGasLimit: U256 = U256::max_value(); + pub BlockGasLimit: U256 = U256::from(u64::MAX); pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; } impl pallet_evm::Config for Runtime { @@ -933,6 +939,9 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; type FindAuthor = (); type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; } pub struct NormalFilter; @@ -1033,6 +1042,7 @@ impl pallet_ethereum::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; } parameter_types! { diff --git a/tests/tests/test-block/test-block-gas.ts b/tests/tests/test-block/test-block-gas.ts index 49f4de7aea..6359d2daa4 100644 --- a/tests/tests/test-block/test-block-gas.ts +++ b/tests/tests/test-block/test-block-gas.ts @@ -9,7 +9,9 @@ import { createContract } from "../../util/transactions"; describeDevMoonbeamAllEthTxTypes("Block Gas - Limit", (context) => { it("should be allowed to the max block gas", async function () { - const { rawTx } = await createContract(context, "MultiplyBy7", { gas: EXTRINSIC_GAS_LIMIT }); + const { rawTx } = await createContract(context, "MultiplyBy7", { + gas: EXTRINSIC_GAS_LIMIT.toString(), + }); const { result } = await context.createBlock(rawTx); expect(result.successful).to.be.true; @@ -21,7 +23,7 @@ describeDevMoonbeamAllEthTxTypes("Block Gas - Limit", (context) => { describeDevMoonbeamAllEthTxTypes("Block Gas - Limit", (context) => { it("should fail setting it over the max block gas", async function () { const { rawTx } = await createContract(context, "MultiplyBy7", { - gas: EXTRINSIC_GAS_LIMIT + 1, + gas: (EXTRINSIC_GAS_LIMIT + 1n).toString(), }); expect( diff --git a/tests/tests/test-eth-fee/test-eth-txn-weights.ts b/tests/tests/test-eth-fee/test-eth-txn-weights.ts index f8824d5701..f68bfb34b4 100644 --- a/tests/tests/test-eth-fee/test-eth-txn-weights.ts +++ b/tests/tests/test-eth-fee/test-eth-txn-weights.ts @@ -27,7 +27,7 @@ describeDevMoonbeam("Ethereum Weight Accounting", (context) => { const { block, result } = await context.createBlock( createTransaction(context, { ...ALITH_TRANSACTION_TEMPLATE, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), maxFeePerGas: 10_000_000_000, maxPriorityFeePerGas: 0, to: baltathar.address, @@ -64,18 +64,18 @@ describeDevMoonbeam("Ethereum Weight Accounting", (context) => { }); it("should correctly refund weight from excess gas_limit supplied", async function () { - const gasAmount = Math.floor(EXTRINSIC_GAS_LIMIT * 0.8); + const gasAmount = (EXTRINSIC_GAS_LIMIT * 8n) / 10n; const tx_1 = await createTransfer(context, baltathar.address, 1, { - gas: gasAmount, + gas: gasAmount.toString(), nonce: 1, }); const tx_2 = await createTransfer(context, charleth.address, 1, { - gas: gasAmount, + gas: gasAmount.toString(), privateKey: BALTATHAR_PRIVATE_KEY, nonce: 0, }); const tx_3 = await createTransfer(context, alith.address, 1, { - gas: gasAmount, + gas: gasAmount.toString(), privateKey: CHARLETH_PRIVATE_KEY, nonce: 0, }); diff --git a/tests/tests/test-eth-tx/test-eth-tx-size.ts b/tests/tests/test-eth-tx/test-eth-tx-size.ts index 9a9faf2496..0be0da75e7 100644 --- a/tests/tests/test-eth-tx/test-eth-tx-size.ts +++ b/tests/tests/test-eth-tx/test-eth-tx-size.ts @@ -9,9 +9,9 @@ import { alith, ALITH_PRIVATE_KEY } from "../../util/accounts"; describeDevMoonbeam("Ethereum Transaction - Large Transaction", (context) => { // function to generate a junk transaction with a specified data size - const generateLargeTxn = async (size: number) => { + const generateLargeTxn = async (size: bigint) => { const byte = "FF"; - const data = "0x" + byte.repeat(size); + const data = "0x" + byte.repeat(Number(size)); let signer = new ethers.Wallet(ALITH_PRIVATE_KEY, context.ethers); @@ -27,12 +27,15 @@ describeDevMoonbeam("Ethereum Transaction - Large Transaction", (context) => { }; // TODO: I'm not sure where this 2000 came from... - const max_size = Math.floor((EXTRINSIC_GAS_LIMIT - 21000) / 16) - 2000; + const max_size = (EXTRINSIC_GAS_LIMIT - 21000n) / 16n - 2000n; it("should accept txns up to known size", async function () { - expect(max_size).to.equal(809187); // our max Ethereum TXN size in bytes + expect(max_size).to.equal(809187n); // our max Ethereum TXN size in bytes - const tx = await generateLargeTxn(max_size); + // max_size - shanghai init cost - create cost + let max_size_shanghai = max_size - 6474n; + + const tx = await generateLargeTxn(max_size_shanghai); const { result } = await context.createBlock(tx); const receipt = await context.web3.eth.getTransactionReceipt(result.hash); @@ -40,7 +43,7 @@ describeDevMoonbeam("Ethereum Transaction - Large Transaction", (context) => { }); it("should reject txns which are too large to pay for", async function () { - const tx = await generateLargeTxn(max_size + 1); + const tx = await generateLargeTxn(max_size + 1n); const txResults = await customWeb3Request(context.web3, "eth_sendRawTransaction", [tx]); // RPC should outright reject this txn -- this is important because it prevents it from being diff --git a/tests/tests/test-fees/test-fee-multiplier.ts b/tests/tests/test-fees/test-fee-multiplier.ts index b66667013f..935a1a3b85 100644 --- a/tests/tests/test-fees/test-fee-multiplier.ts +++ b/tests/tests/test-fees/test-fee-multiplier.ts @@ -125,7 +125,7 @@ describeDevMoonbeam("Max Fee Multiplier", (context) => { // the multiplier (and thereby base_fee) will have decreased very slightly... blockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toBn(); baseFeePerGas = BigInt((await context.web3.eth.getBlock(blockNumber)).baseFeePerGas); - expect(baseFeePerGas).to.equal(124_880_903_689_844n); + expect(baseFeePerGas).to.equal(124880905088510n); const tx = await createContractExecution( context, @@ -148,7 +148,7 @@ describeDevMoonbeam("Max Fee Multiplier", (context) => { expect(withdrawEvents.length).to.equal(1); const withdrawEvent = withdrawEvents[0]; let amount = (withdrawEvent.event.data as any).amount.toBigInt(); - expect(amount).to.equal(11_986_693_540_669_676_340n); + expect(amount).to.equal(11986693674920632350n); }); }); diff --git a/tests/tests/test-fees/test-length-fees.ts b/tests/tests/test-fees/test-length-fees.ts index 7cb0ca58ab..dcf47f267c 100644 --- a/tests/tests/test-fees/test-length-fees.ts +++ b/tests/tests/test-fees/test-length-fees.ts @@ -141,7 +141,7 @@ describeDevMoonbeam("Substrate Length Fees - Ethereum txn Interaction", (context { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", nonce: 0, data: diff --git a/tests/tests/test-gas/test-gas-contract-creation.ts b/tests/tests/test-gas/test-gas-contract-creation.ts index eee2de2a44..e64ccba88c 100644 --- a/tests/tests/test-gas/test-gas-contract-creation.ts +++ b/tests/tests/test-gas/test-gas-contract-creation.ts @@ -14,6 +14,6 @@ describeDevMoonbeam("Estimate Gas - Contract creation", (context) => { from: alith.address, data: contract.byteCode, }) - ).to.equal(156994); + ).to.equal(157029); }); }); diff --git a/tests/tests/test-gas/test-gas-estimation.ts b/tests/tests/test-gas/test-gas-estimation.ts index 266b363123..0df545dc9d 100644 --- a/tests/tests/test-gas/test-gas-estimation.ts +++ b/tests/tests/test-gas/test-gas-estimation.ts @@ -145,12 +145,12 @@ describeDevMoonbeamAllEthTxTypes("Estimate Gas - Handle Gas price", (context) => data: contract.byteCode, gasPrice: "0x0", }); - expect(result).to.equal(174759); + expect(result).to.equal(174798); result = await context.web3.eth.estimateGas({ from: alith.address, data: contract.byteCode, }); - expect(result).to.equal(174759); + expect(result).to.equal(174798); }); }); @@ -215,6 +215,6 @@ describeDevMoonbeamAllEthTxTypes("Estimate Gas - EOA", (context) => { from: PRECOMPILE_BATCH_ADDRESS, data: contract.byteCode, }) - ).to.equal(156994); + ).to.equal(157029); }); }); diff --git a/tests/tests/test-pov/test-evm-over-pov.ts b/tests/tests/test-pov/test-evm-over-pov.ts index ab1209be57..a113fe9424 100644 --- a/tests/tests/test-pov/test-evm-over-pov.ts +++ b/tests/tests/test-pov/test-evm-over-pov.ts @@ -7,13 +7,14 @@ import chaiAsPromised from "chai-as-promised"; import { alith } from "../../util/accounts"; import { describeDevMoonbeam, DevTestContext } from "../../util/setup-dev-tests"; import { createContract, createTransaction } from "../../util/transactions"; -import { MAX_BLOCK_DEV_POV } from "../../util/constants"; +import { MAX_ETH_POV_PER_TX } from "../../util/constants"; import { Contract } from "web3-eth-contract"; +import { expectEVMResult } from "../../util/eth-transactions"; const debug = Debug("test:evm-over-pov"); chaiUse(chaiAsPromised); -interface HeavyContract { +export interface HeavyContract { deployed: boolean; account: string; key: string; @@ -24,7 +25,7 @@ interface HeavyContract { * @param count Number of contracts to deploy * @returns */ -const deployHeavyContracts = async (context: DevTestContext, first = 6000, last = 6999) => { +export const deployHeavyContracts = async (context: DevTestContext, first = 6000, last = 6999) => { // Generate the contract addresses const contracts = await Promise.all( new Array(last - first + 1).fill(0).map(async (_, i) => { @@ -76,11 +77,86 @@ const deployHeavyContracts = async (context: DevTestContext, first = 6000, last return contracts as HeavyContract[]; }; -describeDevMoonbeam("PoV Limit (4.2Mb in Dev)", (context) => { +describeDevMoonbeam("PoV controlled by gasLimit", (context) => { let contractProxy: Contract; let contracts: HeavyContract[]; + const MAX_CONTRACTS = 20; + const EXPECTED_POV_ROUGH = 500_000; // bytes - before("Deploy the contracts", async function () { + before("Deploy the contracts from range 6000-6100", async function () { + // Deploy the CallForwarder contract + const creation = await createContract(context, "CallForwarder"); + contractProxy = creation.contract; + await context.createBlock(creation.rawTx); + + // Deploy heavy contracts (test won't use more than what is needed for reaching max pov) + contracts = await deployHeavyContracts(context, 6000, 6000 + MAX_CONTRACTS); + }); + + it("should allow to include transaction with estimate gas to cover PoV", async function () { + const { result, block } = await context.createBlock( + createTransaction(context, { + to: contractProxy.options.address, + data: contractProxy.methods + .callRange(contracts[0].account, contracts[MAX_CONTRACTS].account) + .encodeABI(), + }) + ); + + debug(`block.proof_size: ${block.proof_size} (successful: ${result.successful})`); + expect(block.proof_size).to.be.at.least(EXPECTED_POV_ROUGH / 1.1); + expect(block.proof_size).to.be.at.most(EXPECTED_POV_ROUGH * 1.1); + expect(result.successful).to.equal(true); + // The transaction should be not be included in the block + }); + + it("should allow to include transaction with enough gas limit to cover PoV", async function () { + const { result, block } = await context.createBlock( + createTransaction(context, { + to: contractProxy.options.address, + data: contractProxy.methods + .callRange(contracts[0].account, contracts[MAX_CONTRACTS].account) + .encodeABI(), + gas: 3_000_000, + }) + ); + + debug(`block.proof_size: ${block.proof_size} (successful: ${result.successful})`); + expect(block.proof_size).to.be.at.least(EXPECTED_POV_ROUGH / 1.1); + expect(block.proof_size).to.be.at.most(EXPECTED_POV_ROUGH * 1.1); + expect(result.successful).to.equal(true); + // The transaction should be not be included in the block + }); + + it("should fail to include transaction without enough gas limit to cover PoV", async function () { + // This execution uses only < 100k Gas in cpu execute but require 2M Gas for PoV. + // We are providing only 1M Gas, so it should fail. + const { result, block } = await context.createBlock( + createTransaction(context, { + to: contractProxy.options.address, + data: contractProxy.methods + .callRange(contracts[0].account, contracts[MAX_CONTRACTS].account) + .encodeABI(), + gas: 1_000_000, + }) + ); + + debug(`block.proof_size: ${block.proof_size} (successful: ${result.successful})`); + // The block still contain the failed (out of gas) transaction so the PoV is still included + // in the block. + // 1M Gas allows ~250k of PoV, so we verify we are within range. + expect(block.proof_size).to.be.at.least(230_000); + expect(block.proof_size).to.be.at.most(300_000); + expect(result.successful).to.equal(true); + expectEVMResult(result.events, "Error", "OutOfGas"); + }); +}); + +describeDevMoonbeam("PoV Limit (3.5Mb in Dev)", (context) => { + let contractProxy: Contract; + let contracts: HeavyContract[]; + + before("Deploy the contracts from range 6000-XXXX", async function () { // Deploy the CallForwarder contract const creation = await createContract(context, "CallForwarder"); contractProxy = creation.contract; @@ -90,42 +166,44 @@ describeDevMoonbeam("PoV Limit (4.2Mb in Dev)", (context) => { contracts = await deployHeavyContracts( context, 6000, - 6000 + Math.ceil(MAX_BLOCK_DEV_POV / 24_000) + 1 + Number(6000n + MAX_ETH_POV_PER_TX / 24_000n + 1n) ); }); it("should allow to produce block just under the PoV Limit", async function () { - const max_contracts = Math.floor(MAX_BLOCK_DEV_POV / 24_000) - 1; + const max_contracts = MAX_ETH_POV_PER_TX / 24_000n - 1n; const { result, block } = await context.createBlock( createTransaction(context, { to: contractProxy.options.address, data: contractProxy.methods - .callRange(contracts[0].account, contracts[max_contracts].account) + .callRange(contracts[0].account, contracts[Number(max_contracts)].account) .encodeABI(), + gas: 13_000_000, }) ); - debug("block.proof_size", block.proof_size); - expect(block.proof_size).to.be.at.least(MAX_BLOCK_DEV_POV - 20_000); - expect(block.proof_size).to.be.at.most(MAX_BLOCK_DEV_POV - 1); + debug(`block.proof_size: ${block.proof_size} (successful: ${result.successful})`); + expect(block.proof_size).to.be.at.least(Number(MAX_ETH_POV_PER_TX - 20_000n)); + expect(block.proof_size).to.be.at.most(Number(MAX_ETH_POV_PER_TX - 1n)); // The transaction should be not be included in the block expect(result.successful).to.equal(true); }); it("should prevent a transaction reaching just over the PoV", async function () { - const max_contracts = Math.ceil(MAX_BLOCK_DEV_POV / 24_000); + const max_contracts = MAX_ETH_POV_PER_TX / 24_000n; const { result, block } = await context.createBlock( createTransaction(context, { to: contractProxy.options.address, data: contractProxy.methods - .callRange(contracts[0].account, contracts[max_contracts].account) + .callRange(contracts[0].account, contracts[Number(max_contracts)].account) .encodeABI(), + gas: 15_000_000, }) ); - debug("block.proof_size", block.proof_size); + debug(`block.proof_size: ${block.proof_size} (successful: ${result.successful})`); // Empty blocks usually do not exceed 10kb, picking 50kb as a safe limit expect(block.proof_size).to.be.at.most(50_000); expect(result.successful).to.equal(false); diff --git a/tests/tests/test-pov/test-precompile-over-pov.ts b/tests/tests/test-pov/test-precompile-over-pov.ts new file mode 100644 index 0000000000..3c7c16fdd3 --- /dev/null +++ b/tests/tests/test-pov/test-precompile-over-pov.ts @@ -0,0 +1,200 @@ +import "@moonbeam-network/api-augment"; + +import { expect, use as chaiUse } from "chai"; +import { ethers } from "ethers"; +import { Interface } from "ethers/src.ts/utils"; +import chaiAsPromised from "chai-as-promised"; + +import { getCompiled } from "../../util/contracts"; +import { describeDevMoonbeam } from "../../util/setup-dev-tests"; +import { createContract, createTransaction } from "../../util/transactions"; +import { PRECOMPILE_BATCH_ADDRESS, MAX_ETH_POV_PER_TX } from "../../util/constants"; +import { Contract } from "web3-eth-contract"; +import { expectEVMResult } from "../../util/eth-transactions"; +import { deployHeavyContracts, HeavyContract } from "./test-evm-over-pov"; + +chaiUse(chaiAsPromised); + +describeDevMoonbeam("PoV precompile test - gasLimit", (context) => { + let contractProxy: Contract; + let contracts: HeavyContract[]; + const MAX_CONTRACTS = 50; + const EXPECTED_POV_ROUGH = 1_000_000; // bytes + let batchInterface: Interface; + let proxyInterface: Interface; + + before("Deploy the contracts from range 6000-6050", async function () { + // Deploy the CallForwarder contract + const creation = await createContract(context, "CallForwarder"); + contractProxy = creation.contract; + await context.createBlock(creation.rawTx); + + // Get the CallForwarder contract interface + proxyInterface = new ethers.utils.Interface(getCompiled("CallForwarder").contract.abi); + + // Deploy heavy contracts + contracts = await deployHeavyContracts(context, 6000, 6000 + MAX_CONTRACTS); + + // Get the interface for Batch precompile + batchInterface = new ethers.utils.Interface( + getCompiled("precompiles/batch/Batch").contract.abi + ); + }); + + it("gas cost should have increased with POV", async function () { + const { result, block } = await context.createBlock( + // Previously this tx cost was ~500K gas -> now it is about 5M due to POV. + // We pass 1M, so it should fail. + createTransaction(context, { + to: PRECOMPILE_BATCH_ADDRESS, + data: batchInterface.encodeFunctionData("batchAll", [ + [contractProxy.options.address], + [], + [ + proxyInterface.encodeFunctionData("callRange", [ + contracts[0].account, + contracts[MAX_CONTRACTS].account, + ]), + ], + [], + ]), + gas: 1_000_000, + }) + ); + + // With 1M gas we are allowed to use ~250k of POV, so verify the range. + // The tx is still included in the block because it contains the failed tx, + // so POV is included in the block as well. + expect(block.proof_size).to.be.at.least(230_000); + expect(block.proof_size).to.be.at.most(290_000); + expect(result.successful).to.equal(true); + expectEVMResult(result.events, "Error", "OutOfGas"); + }); + + it("should be able to create a block using the estimated amount of gas", async function () { + const { result, block } = await context.createBlock( + createTransaction(context, { + to: PRECOMPILE_BATCH_ADDRESS, + data: batchInterface.encodeFunctionData("batchAll", [ + [contractProxy.options.address], + [], + [ + proxyInterface.encodeFunctionData("callRange", [ + contracts[0].account, + contracts[MAX_CONTRACTS].account, + ]), + ], + [], + ]), + }) + ); + expect(block.proof_size).to.be.at.least(EXPECTED_POV_ROUGH / 1.3); + expect(block.proof_size).to.be.at.most(EXPECTED_POV_ROUGH * 1.3); + expect(result.successful).to.equal(true); + expectEVMResult(result.events, "Succeed", "Returned"); + }); + + it("should allow to call a precompile tx with enough gas limit to cover PoV", async function () { + const { result, block } = await context.createBlock( + createTransaction(context, { + to: PRECOMPILE_BATCH_ADDRESS, + data: batchInterface.encodeFunctionData("batchAll", [ + [contractProxy.options.address], + [], + [ + proxyInterface.encodeFunctionData("callRange", [ + contracts[0].account, + contracts[MAX_CONTRACTS].account, + ]), + ], + [], + ]), + gas: 6_000_000, + }) + ); + expect(block.proof_size).to.be.at.least(EXPECTED_POV_ROUGH / 1.3); + expect(block.proof_size).to.be.at.most(EXPECTED_POV_ROUGH * 1.3); + expect(result.successful).to.equal(true); + expectEVMResult(result.events, "Succeed", "Returned"); + }); +}); + +describeDevMoonbeam("PoV precompile test - PoV Limit (3.5Mb in Dev)", (context) => { + let contractProxy: Contract; + let contracts: HeavyContract[]; + let proxyInterface: Interface; + let batchInterface: Interface; + + before("Deploy the contracts from range 6000-XXXX", async function () { + // Deploy the CallForwarder contract + const creation = await createContract(context, "CallForwarder"); + contractProxy = creation.contract; + await context.createBlock(creation.rawTx); + + // Get the CallForwarder contract interface + proxyInterface = new ethers.utils.Interface(getCompiled("CallForwarder").contract.abi); + + // Deploy heavy contracts (test won't use more than what is needed for reaching max pov) + contracts = await deployHeavyContracts( + context, + 6000, + Number(6000n + MAX_ETH_POV_PER_TX / 24_000n + 1n) + ); + + // Get the interface for Batch precompile + batchInterface = new ethers.utils.Interface( + getCompiled("precompiles/batch/Batch").contract.abi + ); + }); + + it("should allow to produce block under the PoV Limit with precompile tx", async function () { + const max_contracts = MAX_ETH_POV_PER_TX / 24_000n - 1n; + + const { result, block } = await context.createBlock( + createTransaction(context, { + to: PRECOMPILE_BATCH_ADDRESS, + data: batchInterface.encodeFunctionData("batchAll", [ + [contractProxy.options.address], + [], + [ + proxyInterface.encodeFunctionData("callRange", [ + contracts[0].account, + contracts[Number(max_contracts)].account, + ]), + ], + [], + ]), + gas: 13_000_000, + }) + ); + expect(block.proof_size).to.be.at.least(Number(MAX_ETH_POV_PER_TX - 20_000n)); + expect(block.proof_size).to.be.at.most(Number(MAX_ETH_POV_PER_TX - 1n)); + expect(result.successful).to.equal(true); + }); + + it("should prevent a tx reaching just over the PoV with a precompile tx", async function () { + const max_contracts = MAX_ETH_POV_PER_TX / 24_000n; + + const { result, block } = await context.createBlock( + createTransaction(context, { + to: PRECOMPILE_BATCH_ADDRESS, + data: batchInterface.encodeFunctionData("batchAll", [ + [contractProxy.options.address], + [], + [ + proxyInterface.encodeFunctionData("callRange", [ + contracts[0].account, + contracts[Number(max_contracts)].account, + ]), + ], + [], + ]), + gas: 15_000_000, + }) + ); + + // Empty blocks usually do not exceed 10kb, picking 50kb as a safe limit + expect(block.proof_size).to.be.at.most(50_000); + expect(result.successful).to.equal(false); + }); +}); diff --git a/tests/tests/test-precompile/test-precompile-local-assets-erc20.ts b/tests/tests/test-precompile/test-precompile-local-assets-erc20.ts index ca7096b34b..9124f10355 100644 --- a/tests/tests/test-precompile/test-precompile-local-assets-erc20.ts +++ b/tests/tests/test-precompile/test-precompile-local-assets-erc20.ts @@ -53,6 +53,16 @@ const LOCAL_ASSET_EXTENDED_ERC20_INTERFACE = new ethers.utils.Interface( const ROLES_INTERFACE = new ethers.utils.Interface(ROLES_CONTRACT.contract.abi); +function call_params(data, to) { + return { + from: alith.address, + value: "0x0", + to, + data: data, + gasPrice: GAS_PRICE, + }; +} + describeDevMoonbeamAllEthTxTypes( "Precompiles - Assets-ERC20 Wasm", (context) => { @@ -92,14 +102,13 @@ describeDevMoonbeamAllEthTxTypes( [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -117,15 +126,13 @@ describeDevMoonbeamAllEthTxTypes( "symbol", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -143,15 +150,13 @@ describeDevMoonbeamAllEthTxTypes( "decimals", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -165,15 +170,13 @@ describeDevMoonbeamAllEthTxTypes( "balanceOf", [baltathar.address] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); let amount = new BN(100000000000000); @@ -188,14 +191,13 @@ describeDevMoonbeamAllEthTxTypes( "totalSupply", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -211,14 +213,13 @@ describeDevMoonbeamAllEthTxTypes( "owner", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -232,14 +233,13 @@ describeDevMoonbeamAllEthTxTypes( "freezer", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -253,14 +253,13 @@ describeDevMoonbeamAllEthTxTypes( "admin", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); @@ -274,14 +273,13 @@ describeDevMoonbeamAllEthTxTypes( "issuer", [] ); + const params = call_params(data, assetAddress); + const estimate = await customWeb3Request(context.web3, "eth_estimateGas", [params]); + const tx_call = await customWeb3Request(context.web3, "eth_call", [ { - from: alith.address, - value: "0x0", - gas: "0x10000", - gasPrice: GAS_PRICE, - to: assetAddress, - data: data, + gas: estimate.result, + ...params, }, ]); diff --git a/tests/tests/test-precompile/test-precompile-modexp.ts b/tests/tests/test-precompile/test-precompile-modexp.ts index b620af6902..3e37fe7a3a 100644 --- a/tests/tests/test-precompile/test-precompile-modexp.ts +++ b/tests/tests/test-precompile/test-precompile-modexp.ts @@ -70,7 +70,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -122,7 +122,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -157,7 +157,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -192,7 +192,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -227,7 +227,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -262,7 +262,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -297,7 +297,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -332,7 +332,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -367,7 +367,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -402,7 +402,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -437,7 +437,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -472,7 +472,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -507,7 +507,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -542,7 +542,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -577,7 +577,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -612,7 +612,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -647,7 +647,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, @@ -699,7 +699,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: inputData, }, @@ -730,7 +730,7 @@ describeDevMoonbeam("Precompiles - modexp", (context) => { { from: alith.address, to: MODEXP_PRECOMPILE_ADDRESS, - gas: EXTRINSIC_GAS_LIMIT, + gas: EXTRINSIC_GAS_LIMIT.toString(), value: "0x00", data: "0x" + inputData, }, diff --git a/tests/tests/test-precompile/test-precompile-xcm-utils.ts b/tests/tests/test-precompile/test-precompile-xcm-utils.ts index d7f0bd8e83..d232e81cb1 100644 --- a/tests/tests/test-precompile/test-precompile-xcm-utils.ts +++ b/tests/tests/test-precompile/test-precompile-xcm-utils.ts @@ -180,16 +180,16 @@ describeDevMoonbeamAllEthTxTypes("Precompiles - xcm utils", (context) => { xcmMessage ) as any; - await context.createBlock( - createTransaction(context, { - ...ALITH_TRANSACTION_TEMPLATE, - to: PRECOMPILE_XCM_UTILS_ADDRESS, - data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ - receivedMessage.toU8a(), - 2_000_000_000, - ]), - }) - ); + let payload = { + ...ALITH_TRANSACTION_TEMPLATE, + to: PRECOMPILE_XCM_UTILS_ADDRESS, + data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ + receivedMessage.toU8a(), + 2_000_000_000, + ]), + }; + delete payload["gas"]; + await context.createBlock(createTransaction(context, payload)); // Tokens transferred const testAccountBalance = ( @@ -228,16 +228,17 @@ describeDevMoonbeam( xcmMessage ) as any; - const { result } = await context.createBlock( - createTransaction(context, { - ...ALITH_TRANSACTION_TEMPLATE, - to: PRECOMPILE_XCM_UTILS_ADDRESS, - data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ - receivedMessage.toU8a(), - 2_000_000_000, - ]), - }) - ); + let payload = { + ...ALITH_TRANSACTION_TEMPLATE, + to: PRECOMPILE_XCM_UTILS_ADDRESS, + data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ + receivedMessage.toU8a(), + 2_000_000_000, + ]), + }; + delete payload["gas"]; + + const { result } = await context.createBlock(createTransaction(context, payload)); expectEVMResult(result.events, "Revert"); const revertReason = await extractRevertReason(result.hash, context.ethers); @@ -279,17 +280,18 @@ describeDevMoonbeam( xcmMessage ) as any; - const { result } = await context.createBlock( - createTransaction(context, { - ...ALITH_TRANSACTION_TEMPLATE, - gasPrice: 1_000_000_000_000, - to: PRECOMPILE_XCM_UTILS_ADDRESS, - data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ - receivedMessage.toU8a(), - 2_000_000_000, - ]), - }) - ); + let payload = { + ...ALITH_TRANSACTION_TEMPLATE, + gasPrice: 1_000_000_000_000, + to: PRECOMPILE_XCM_UTILS_ADDRESS, + data: XCM_UTILSTRANSACTOR_INTERFACE.encodeFunctionData("xcmExecute", [ + receivedMessage.toU8a(), + 2_000_000_000, + ]), + }; + delete payload["gas"]; + + const { result } = await context.createBlock(createTransaction(context, payload)); expectEVMResult(result.events, "Revert"); const revertReason = await extractRevertReason(result.hash, context.ethers); diff --git a/tests/tests/test-receipt/test-receipt-revert.ts b/tests/tests/test-receipt/test-receipt-revert.ts index c067b82197..d0adf2bc63 100644 --- a/tests/tests/test-receipt/test-receipt-revert.ts +++ b/tests/tests/test-receipt/test-receipt-revert.ts @@ -15,9 +15,9 @@ describeDevMoonbeamAllEthTxTypes("Receipt - Revert", (context) => { expect(receipt).to.include({ blockNumber: 1, contractAddress: "0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3", - cumulativeGasUsed: 54602, + cumulativeGasUsed: 54610, from: "0xf24ff3a9cf04c71dbc94d0b566f7a27b94566cac", - gasUsed: 54602, + gasUsed: 54610, to: null, transactionHash: result.hash, transactionIndex: 0, diff --git a/tests/tests/test-xcm/test-mock-hrmp-transact-ethereum.ts b/tests/tests/test-xcm/test-mock-hrmp-transact-ethereum.ts index 6e6a94e887..aeaa41825d 100644 --- a/tests/tests/test-xcm/test-mock-hrmp-transact-ethereum.ts +++ b/tests/tests/test-xcm/test-mock-hrmp-transact-ethereum.ts @@ -19,6 +19,8 @@ import { import { describeDevMoonbeam } from "../../util/setup-dev-tests"; +import { GAS_LIMIT_POV_RATIO } from "../../util/constants"; + import { createContract } from "../../util/transactions"; import { expectOk } from "../../util/expect"; @@ -1296,10 +1298,12 @@ describeDevMoonbeam("Mock XCM - transact ETHEREUM input size check succeeds", (c // Matches the BoundedVec limit in the runtime. const CALL_INPUT_SIZE_LIMIT = Math.pow(2, 16); + const GAS_LIMIT = 1000000; + const xcmTransactions = [ { V1: { - gas_limit: 1000000, + gas_limit: GAS_LIMIT, fee_payment: { Auto: { Low: null, @@ -1318,7 +1322,7 @@ describeDevMoonbeam("Mock XCM - transact ETHEREUM input size check succeeds", (c }, { V2: { - gas_limit: 1000000, + gas_limit: GAS_LIMIT, action: { Call: contractDeployed.options.address, }, @@ -1349,7 +1353,10 @@ describeDevMoonbeam("Mock XCM - transact ETHEREUM input size check succeeds", (c fungible: transferredBalance / 2n, }, ], - weight_limit: new BN(40000000000), + weight_limit: { + refTime: 40000000000, + proofSize: (GAS_LIMIT / GAS_LIMIT_POV_RATIO) * 2, + } as any, descend_origin: sendingAddress, }) .descend_origin() @@ -1357,14 +1364,17 @@ describeDevMoonbeam("Mock XCM - transact ETHEREUM input size check succeeds", (c .buy_execution() .push_any({ Transact: { - originType: "SovereignAccount", - requireWeightAtMost: new BN(30000000000), + originKind: "SovereignAccount", + requireWeightAtMost: { + refTime: 30000000000, + proofSize: GAS_LIMIT / GAS_LIMIT_POV_RATIO, + }, call: { encoded: transferCallEncoded, }, }, }) - .as_v2(); + .as_v3(); // Send an XCM and create block to execute it await injectHrmpMessageAndSeal(context, 1, { @@ -1540,12 +1550,14 @@ describeDevMoonbeam("Mock XCM - receive horizontal transact ETHEREUM (transfer)" const amountToTransfer = transferredBalance / 10n; + const GAS_LIMIT = 500_000; + // We will put a very high gas limit. However, the weight accounted // for the block should only const xcmTransactions = [ { V1: { - gas_limit: 500_000, + gas_limit: GAS_LIMIT, fee_payment: { Auto: { Low: null, @@ -1588,7 +1600,10 @@ describeDevMoonbeam("Mock XCM - receive horizontal transact ETHEREUM (transfer)" fungible: targetXcmFee, }, ], - weight_limit: new BN(targetXcmWeight.toString()), + weight_limit: { + refTime: targetXcmWeight, + proofSize: (GAS_LIMIT / GAS_LIMIT_POV_RATIO) * 2, + } as any, descend_origin: sendingAddress, }) .descend_origin() @@ -1596,15 +1611,18 @@ describeDevMoonbeam("Mock XCM - receive horizontal transact ETHEREUM (transfer)" .buy_execution() .push_any({ Transact: { - originType: "SovereignAccount", + originKind: "SovereignAccount", // 500_000 gas limit + db read - requireWeightAtMost: new BN(12_500_000_000).add(new BN(25_000_000)), + requireWeightAtMost: { + refTime: 12_525_000_000, + proofSize: GAS_LIMIT / GAS_LIMIT_POV_RATIO, + }, call: { encoded: transferCallEncoded, }, }, }) - .as_v2(); + .as_v3(); // Send an XCM and create block to execute it await injectHrmpMessageAndSeal(context, 1, { diff --git a/tests/util/constants.ts b/tests/util/constants.ts index 7c35624113..e340ff5f40 100644 --- a/tests/util/constants.ts +++ b/tests/util/constants.ts @@ -34,30 +34,41 @@ export const VOTE_AMOUNT = 10n * GLMR; export const MIN_GLMR_STAKING = 1000n * GLMR; export const MIN_GLMR_DELEGATOR = 1n * GLMR; -// Maximum PoV size in bytes allowed for a manual sealing dev block -export const MAX_BLOCK_DEV_POV = 4 * 1024 * 1024 + 512; +// Weight correspond to 1 picosecond +export const WEIGHT_PER_SECOND = 1_000_000_000_000n; // Current gas per second -export const GAS_PER_SECOND = 40_000_000; -// The real computation is 1_000_000_000_000 / 40_000_000, but we simplify to avoid bigint. -export const GAS_PER_WEIGHT = 1_000_000 / 40; +export const GAS_PER_SECOND = 40_000_000n; +export const GAS_PER_WEIGHT = WEIGHT_PER_SECOND / GAS_PER_SECOND; + +// Maximum Gas to PoV ratio used in the gasometer +export const GAS_PER_POV_BYTES = 4n; // Our weight limit is 500ms. -export const BLOCK_TX_LIMIT = GAS_PER_SECOND * 0.5; +export const BLOCK_WEIGHT_LIMIT = WEIGHT_PER_SECOND / 2n; -// Current implementation is limiting block transactions to 75% of the block gas limit -export const BLOCK_TX_GAS_LIMIT = BLOCK_TX_LIMIT * 0.75; -export const EXTRINSIC_BASE_WEIGHT = 250_000_000; +// Block limit is 20M gas but only 75% is used for normal transactions, limiting to 15M Gas +export const BLOCK_GAS_LIMIT = BLOCK_WEIGHT_LIMIT / GAS_PER_WEIGHT; -// Maximum extrinsic weight is taken from the max allowed transaction weight per block, +// Maximum extrinsic weight is taken from the max allowed transaction weight per block (75%), // minus the block initialization (10%) and minus the extrinsic base cost. -export const EXTRINSIC_GAS_LIMIT = BLOCK_TX_GAS_LIMIT - BLOCK_TX_LIMIT * 0.1; +export const EXTRINSIC_GAS_LIMIT = (BLOCK_GAS_LIMIT * 3n) / 4n - BLOCK_GAS_LIMIT / 10n; + +// Maximum PoV size in bytes allowed for a manual sealing dev block by substrate. +export const MAX_BLOCK_DEV_POV = 4 * 1024 * 1024 + 512; + +// Maximum PoV size in bytes allowed by the gasometer for one ethereum transaction +export const MAX_ETH_POV_PER_TX = EXTRINSIC_GAS_LIMIT / GAS_PER_POV_BYTES; + +export const EXTRINSIC_BASE_WEIGHT = 250_000_000; // Weight per gas mapping export const WEIGHT_PER_GAS = 1_000_000_000_000n / 40_000_000n; export const MIN_GAS_PRICE = 10_000_000_000n; +export const GAS_LIMIT_POV_RATIO = 4; + export const PRECOMPILE_PARACHAIN_STAKING_ADDRESS = "0x0000000000000000000000000000000000000800"; export const PRECOMPILE_CROWDLOAN_REWARDS_ADDRESS = "0x0000000000000000000000000000000000000801"; export const PRECOMPILE_NATIVE_ERC20_ADDRESS = "0x0000000000000000000000000000000000000802";