From 548c1d318ff051efa1ddc3fef375a68e13621f51 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Mon, 18 Aug 2025 13:50:00 -0300 Subject: [PATCH 01/16] bump zombienet-sdk version --- Cargo.lock | 549 ++++++++++++++++++++++++++++++++++++++++++----------- Cargo.toml | 6 +- 2 files changed, 444 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c4d0344bf222..ae3e8df895111 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,7 +179,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bytes", "smol_str", ] @@ -603,7 +603,7 @@ dependencies = [ "ark-ff-macros 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "digest 0.10.7", "educe", "itertools 0.13.0", @@ -780,7 +780,7 @@ checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive 0.5.0", "ark-std 0.5.0", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "digest 0.10.7", "num-bigint", "rayon", @@ -906,9 +906,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "asn1-rs" @@ -919,7 +919,7 @@ dependencies = [ "asn1-rs-derive 0.5.0", "asn1-rs-impl", "displaydoc", - "nom", + "nom 7.1.3", "num-traits", "rusticata-macros", "thiserror 1.0.65", @@ -935,7 +935,7 @@ dependencies = [ "asn1-rs-derive 0.6.0", "asn1-rs-impl", "displaydoc", - "nom", + "nom 7.1.3", "num-traits", "rusticata-macros", "thiserror 2.0.12", @@ -1980,7 +1980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "constant_time_eq 0.3.0", ] @@ -1991,7 +1991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "constant_time_eq 0.2.6", ] @@ -2002,7 +2002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "cc", "cfg-if", "constant_time_eq 0.3.0", @@ -2951,7 +2951,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom", + "nom 7.1.3", ] [[package]] @@ -3388,7 +3388,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ - "nom", + "nom 7.1.3", "proc-macro2 1.0.95", "quote 1.0.40", "syn 1.0.109", @@ -3544,6 +3544,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -5323,7 +5332,7 @@ checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs 0.6.1", "displaydoc", - "nom", + "nom 7.1.3", "num-bigint", "num-traits", "rusticata-macros", @@ -5337,7 +5346,7 @@ checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs 0.7.0", "displaydoc", - "nom", + "nom 7.1.3", "num-bigint", "num-traits", "rusticata-macros", @@ -5402,7 +5411,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2 1.0.95", "quote 1.0.40", "rustc_version 0.4.0", @@ -5445,6 +5454,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ + "convert_case 0.7.1", "proc-macro2 1.0.95", "quote 1.0.40", "syn 2.0.98", @@ -6177,7 +6187,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "auto_impl", "bytes", ] @@ -6188,7 +6198,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "auto_impl", "bytes", ] @@ -6586,6 +6596,20 @@ dependencies = [ "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "frame-decode" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e56c0e51972d7b26ff76966c4d0f2307030df9daa5ce0885149ece1ab7ca5ad" +dependencies = [ + "frame-metadata 23.0.0", + "parity-scale-codec", + "scale-decode 0.16.0", + "scale-info", + "scale-type-resolver", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "frame-election-provider-solution-type" version = "13.0.0" @@ -7620,7 +7644,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", ] [[package]] @@ -8515,7 +8539,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d72f2fb8cfd27f6c52ea7d0528df594f7f2ed006feac153e9393ec567aafea98" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bitvec", "byte-slice-cast", "const_format", @@ -9281,7 +9305,7 @@ version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced237d0bd84bbebb7c2cad4c073160dacb4fe40534963c32ed6d4c6bb7702a3" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "asynchronous-codec 0.7.0", "bytes", "either", @@ -10122,7 +10146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", @@ -10681,6 +10705,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "nonempty" version = "0.7.0" @@ -10786,7 +10819,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "itoa", ] @@ -11743,7 +11776,7 @@ dependencies = [ "sp-runtime", "tempfile", "toml", - "twox-hash", + "twox-hash 1.6.3", ] [[package]] @@ -14073,7 +14106,7 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bitvec", "byte-slice-cast", "bytes", @@ -16957,9 +16990,9 @@ dependencies = [ [[package]] name = "polkavm-common" -version = "0.9.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" +checksum = "31ff33982a807d8567645d4784b9b5d7ab87bcb494f534a57cadd9012688e102" [[package]] name = "polkavm-common" @@ -16984,11 +17017,11 @@ dependencies = [ [[package]] name = "polkavm-derive" -version = "0.9.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" +checksum = "c2eb703f3b6404c13228402e98a5eae063fd16b8f58afe334073ec105ee4117e" dependencies = [ - "polkavm-derive-impl-macro 0.9.0", + "polkavm-derive-impl-macro 0.18.0", ] [[package]] @@ -17011,11 +17044,11 @@ dependencies = [ [[package]] name = "polkavm-derive-impl" -version = "0.9.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" +checksum = "2f2116a92e6e96220a398930f4c8a6cda1264206f3e2034fc9982bfd93f261f7" dependencies = [ - "polkavm-common 0.9.0", + "polkavm-common 0.18.0", "proc-macro2 1.0.95", "quote 1.0.40", "syn 2.0.98", @@ -17047,11 +17080,11 @@ dependencies = [ [[package]] name = "polkavm-derive-impl-macro" -version = "0.9.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" +checksum = "48c16669ddc7433e34c1007d31080b80901e3e8e523cb9d4b441c3910cf9294b" dependencies = [ - "polkavm-derive-impl 0.9.0", + "polkavm-derive-impl 0.18.1", "syn 2.0.98", ] @@ -18758,7 +18791,7 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "nom", + "nom 7.1.3", ] [[package]] @@ -18965,7 +18998,7 @@ checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" dependencies = [ "byteorder", "thiserror-core", - "twox-hash", + "twox-hash 1.6.3", ] [[package]] @@ -18978,6 +19011,12 @@ dependencies = [ "derive_more 0.99.17", ] +[[package]] +name = "ruzstd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" + [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -19739,7 +19778,7 @@ name = "sc-mixnet" version = "0.4.0" dependencies = [ "array-bytes 6.2.2", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "blake2 0.10.6", "bytes", "futures", @@ -20808,7 +20847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "curve25519-dalek-ng", "merlin", "rand_core 0.6.4", @@ -20826,7 +20865,7 @@ checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" dependencies = [ "aead", "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "curve25519-dalek", "getrandom_or_panic", "merlin", @@ -21447,7 +21486,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "async-lock 2.8.0", "atomic-take", "base64 0.21.7", @@ -21470,7 +21509,7 @@ dependencies = [ "libsecp256k1", "merlin", "no-std-net", - "nom", + "nom 7.1.3", "num-bigint", "num-rational", "num-traits", @@ -21489,7 +21528,7 @@ dependencies = [ "slab", "smallvec", "soketto 0.7.1", - "twox-hash", + "twox-hash 1.6.3", "wasmi 0.31.2", "x25519-dalek", "zeroize", @@ -21501,7 +21540,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "966e72d77a3b2171bb7461d0cb91f43670c63558c62d7cf42809cae6c8b6b818" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "async-lock 3.4.0", "atomic-take", "base64 0.22.1", @@ -21524,7 +21563,7 @@ dependencies = [ "libm", "libsecp256k1", "merlin", - "nom", + "nom 7.1.3", "num-bigint", "num-rational", "num-traits", @@ -21543,12 +21582,66 @@ dependencies = [ "slab", "smallvec", "soketto 0.8.0", - "twox-hash", + "twox-hash 1.6.3", "wasmi 0.32.3", "x25519-dalek", "zeroize", ] +[[package]] +name = "smoldot" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16e5723359f0048bf64bfdfba64e5732a56847d42c4fd3fe56f18280c813413" +dependencies = [ + "arrayvec 0.7.6", + "async-lock 3.4.0", + "atomic-take", + "base64 0.22.1", + "bip39", + "blake2-rfc", + "bs58", + "chacha20", + "crossbeam-queue", + "derive_more 2.0.1", + "ed25519-zebra", + "either", + "event-listener 5.3.1", + "fnv", + "futures-lite 2.3.0", + "futures-util", + "hashbrown 0.15.3", + "hex", + "hmac 0.12.1", + "itertools 0.14.0", + "libm", + "libsecp256k1", + "merlin", + "nom 8.0.0", + "num-bigint", + "num-rational", + "num-traits", + "pbkdf2", + "pin-project", + "poly1305", + "rand 0.8.5", + "rand_chacha 0.3.1", + "ruzstd 0.8.1", + "schnorrkel 0.11.4", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "siphasher 1.0.1", + "slab", + "smallvec", + "soketto 0.8.0", + "twox-hash 2.1.1", + "wasmi 0.40.0", + "x25519-dalek", + "zeroize", +] + [[package]] name = "smoldot-light" version = "0.9.0" @@ -21621,6 +21714,42 @@ dependencies = [ "zeroize", ] +[[package]] +name = "smoldot-light" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bba9e591716567d704a8252feeb2f1261a286e1e2cbdd4e49e9197c34a14e2" +dependencies = [ + "async-channel 2.3.0", + "async-lock 3.4.0", + "base64 0.22.1", + "blake2-rfc", + "bs58", + "derive_more 2.0.1", + "either", + "event-listener 5.3.1", + "fnv", + "futures-channel", + "futures-lite 2.3.0", + "futures-util", + "hashbrown 0.15.3", + "hex", + "itertools 0.14.0", + "log", + "lru 0.12.3", + "parking_lot 0.12.3", + "pin-project", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "siphasher 1.0.1", + "slab", + "smol 2.0.2", + "smoldot 0.19.4", + "zeroize", +] + [[package]] name = "snap" version = "1.1.0" @@ -22621,10 +22750,11 @@ dependencies = [ [[package]] name = "sp-core" -version = "35.0.0" +version = "36.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4532774405a712a366a98080cbb4daa28c38ddff0ec595902ad6ee6a78a809f8" +checksum = "1cdbb58c21e6b27f2aadf3ff0c8b20a8ead13b9dfe63f46717fd59334517f3b4" dependencies = [ + "ark-vrf", "array-bytes 6.2.2", "bitflags 1.3.2", "blake2 0.10.6", @@ -22655,7 +22785,7 @@ dependencies = [ "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-externalities 0.30.0", - "sp-runtime-interface 29.0.0", + "sp-runtime-interface 29.0.1", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-storage 22.0.0", "ss58-registry", @@ -22719,7 +22849,7 @@ dependencies = [ "sha2 0.10.8", "sha3", "sp-crypto-hashing-proc-macro", - "twox-hash", + "twox-hash 1.6.3", ] [[package]] @@ -22733,7 +22863,7 @@ dependencies = [ "digest 0.10.7", "sha2 0.10.8", "sha3", - "twox-hash", + "twox-hash 1.6.3", ] [[package]] @@ -23014,20 +23144,20 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "29.0.0" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e83d940449837a8b2a01b4d877dd22d896fd14d3d3ade875787982da994a33" +checksum = "e99db36a7aff44c335f5d5b36c182a3e0cac61de2fefbe2eeac6af5fb13f63bf" dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive 0.18.0", "primitive-types 0.13.1", "sp-externalities 0.30.0", "sp-runtime-interface-proc-macro 18.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-storage 22.0.0", - "sp-tracing 17.0.1", + "sp-tracing 17.1.0", "sp-wasm-interface 21.0.1", "static_assertions", ] @@ -23237,9 +23367,9 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "17.0.1" +version = "17.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf641a1d17268c8fcfdb8e0fa51a79c2d4222f4cfda5f3944dbdbc384dced8d5" +checksum = "6147a5b8c98b9ed4bf99dc033fab97a468b4645515460974c8784daeb7c35433" dependencies = [ "parity-scale-codec", "tracing", @@ -23404,7 +23534,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "nom", + "nom 7.1.3", "unicode_categories", ] @@ -24245,7 +24375,7 @@ dependencies = [ "serde_json", "subxt 0.41.0", "subxt-core 0.41.0", - "subxt-rpcs", + "subxt-rpcs 0.41.0", "subxt-signer 0.41.0", "termplot", "thiserror 2.0.12", @@ -24316,7 +24446,6 @@ dependencies = [ "futures", "hex", "impl-serde", - "jsonrpsee", "parity-scale-codec", "polkadot-sdk 0.7.0", "primitive-types 0.13.1", @@ -24328,15 +24457,11 @@ dependencies = [ "serde", "serde_json", "subxt-core 0.38.0", - "subxt-lightclient 0.38.0", "subxt-macro 0.38.0", "subxt-metadata 0.38.0", "thiserror 1.0.65", - "tokio", - "tokio-util", "tracing", "url", - "wasm-bindgen-futures", "web-time", ] @@ -24367,7 +24492,44 @@ dependencies = [ "subxt-lightclient 0.41.0", "subxt-macro 0.41.0", "subxt-metadata 0.41.0", - "subxt-rpcs", + "subxt-rpcs 0.41.0", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "tracing", + "url", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "subxt" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74791ddeaaa6de42e7cc8a715c83eb73303f513f90af701fd07eb2caad92ed84" +dependencies = [ + "async-trait", + "derive-where", + "either", + "frame-metadata 23.0.0", + "futures", + "hex", + "jsonrpsee", + "parity-scale-codec", + "primitive-types 0.13.1", + "scale-bits 0.7.0", + "scale-decode 0.16.0", + "scale-encode 0.10.0", + "scale-info", + "scale-value 0.18.0", + "serde", + "serde_json", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt-core 0.43.0", + "subxt-lightclient 0.43.0", + "subxt-macro 0.43.0", + "subxt-metadata 0.43.0", + "subxt-rpcs 0.43.0", "thiserror 2.0.12", "tokio", "tokio-util", @@ -24411,6 +24573,23 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "subxt-codegen" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1728caecd9700391e78cc30dc298221d6f5ca0ea28258a452aa76b0b7c229842" +dependencies = [ + "heck 0.5.0", + "parity-scale-codec", + "proc-macro2 1.0.95", + "quote 1.0.40", + "scale-info", + "scale-typegen 0.11.1", + "subxt-metadata 0.43.0", + "syn 2.0.98", + "thiserror 2.0.12", +] + [[package]] name = "subxt-core" version = "0.38.0" @@ -24470,18 +24649,48 @@ dependencies = [ "tracing", ] +[[package]] +name = "subxt-core" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25338dd11ae34293b8d0c5807064f2e00194ba1bd84cccfa694030c8d185b941" +dependencies = [ + "base58", + "blake2 0.10.6", + "derive-where", + "frame-decode 0.8.3", + "frame-metadata 23.0.0", + "hashbrown 0.14.5", + "hex", + "impl-serde", + "keccak-hash", + "parity-scale-codec", + "primitive-types 0.13.1", + "scale-bits 0.7.0", + "scale-decode 0.16.0", + "scale-encode 0.10.0", + "scale-info", + "scale-value 0.18.0", + "serde", + "serde_json", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt-metadata 0.43.0", + "thiserror 2.0.12", + "tracing", +] + [[package]] name = "subxt-lightclient" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534d4b725183a9fa09ce0e0f135674473297fdd97dee4d683f41117f365ae997" +checksum = "ce07c2515b2e63b85ec3043fe4461b287af0615d4832c2fe6e81ba780b906bc0" dependencies = [ "futures", "futures-util", "serde", "serde_json", "smoldot-light 0.16.2", - "thiserror 1.0.65", + "thiserror 2.0.12", "tokio", "tokio-stream", "tracing", @@ -24489,15 +24698,15 @@ dependencies = [ [[package]] name = "subxt-lightclient" -version = "0.41.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce07c2515b2e63b85ec3043fe4461b287af0615d4832c2fe6e81ba780b906bc0" +checksum = "9097ef356e534ce0b6a50b95233512afc394347b971a4f929c4830adc52bbc6f" dependencies = [ "futures", "futures-util", "serde", "serde_json", - "smoldot-light 0.16.2", + "smoldot-light 0.17.2", "thiserror 2.0.12", "tokio", "tokio-stream", @@ -24536,6 +24745,23 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "subxt-macro" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69516e8ff0e9340a0f21b8398da7f997571af4734ee81deada5150a2668c8443" +dependencies = [ + "darling", + "parity-scale-codec", + "proc-macro-error2", + "quote 1.0.40", + "scale-typegen 0.11.1", + "subxt-codegen 0.43.0", + "subxt-metadata 0.43.0", + "subxt-utils-fetchmetadata 0.43.0", + "syn 2.0.98", +] + [[package]] name = "subxt-metadata" version = "0.38.0" @@ -24565,6 +24791,21 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "subxt-metadata" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c134068711c0c46906abc0e6e4911204420331530738e18ca903a5469364d9f" +dependencies = [ + "frame-decode 0.8.3", + "frame-metadata 23.0.0", + "hashbrown 0.14.5", + "parity-scale-codec", + "scale-info", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.12", +] + [[package]] name = "subxt-rpcs" version = "0.41.0" @@ -24591,21 +24832,46 @@ dependencies = [ "url", ] +[[package]] +name = "subxt-rpcs" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25de7727144780d780a6a7d78bbfd28414b8adbab68b05e87329c367d7705be4" +dependencies = [ + "derive-where", + "frame-metadata 23.0.0", + "futures", + "hex", + "impl-serde", + "jsonrpsee", + "parity-scale-codec", + "primitive-types 0.13.1", + "serde", + "serde_json", + "subxt-core 0.43.0", + "subxt-lightclient 0.43.0", + "thiserror 2.0.12", + "tokio-util", + "tracing", + "url", +] + [[package]] name = "subxt-signer" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7a336d6a1f86f126100a4a717be58352de4c8214300c4f7807f974494efdb9" +checksum = "4a2370298a210ed1df26152db7209a85e0ed8cfbce035309c3b37f7b61755377" dependencies = [ "base64 0.22.1", + "bip32", "bip39", "cfg-if", "crypto_secretbox", "hex", "hmac 0.12.1", + "keccak-hash", "parity-scale-codec", "pbkdf2", - "polkadot-sdk 0.7.0", "regex", "schnorrkel 0.11.4", "scrypt", @@ -24614,24 +24880,24 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "subxt-core 0.38.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt-core 0.41.0", + "thiserror 2.0.12", "zeroize", ] [[package]] name = "subxt-signer" -version = "0.41.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a2370298a210ed1df26152db7209a85e0ed8cfbce035309c3b37f7b61755377" +checksum = "9a9bd240ae819f64ac6898d7ec99a88c8b838dba2fb9d83b843feb70e77e34c8" dependencies = [ "base64 0.22.1", - "bip32", "bip39", "cfg-if", "crypto_secretbox", "hex", "hmac 0.12.1", - "keccak-hash", "parity-scale-codec", "pbkdf2", "regex", @@ -24643,7 +24909,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subxt-core 0.41.0", + "subxt-core 0.43.0", "thiserror 2.0.12", "zeroize", ] @@ -24670,6 +24936,17 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "subxt-utils-fetchmetadata" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4fb8fd6b16ecd3537a29d70699f329a68c1e47f70ed1a46d64f76719146563" +dependencies = [ + "hex", + "parity-scale-codec", + "thiserror 2.0.12", +] + [[package]] name = "sval" version = "2.6.1" @@ -25841,6 +26118,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "twox-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" + [[package]] name = "typenum" version = "1.16.0" @@ -26329,7 +26612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a" dependencies = [ "leb128fmt", - "wasmparser", + "wasmparser 0.235.0", ] [[package]] @@ -26415,17 +26698,33 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50386c99b9c32bd2ed71a55b6dd4040af2580530fae8bdb9a6576571a80d0cca" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "multi-stash", "num-derive", "num-traits", "smallvec", "spin 0.9.8", - "wasmi_collections", + "wasmi_collections 0.32.3", "wasmi_core 0.32.3", "wasmparser-nostd", ] +[[package]] +name = "wasmi" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19af97fcb96045dd1d6b4d23e2b4abdbbe81723dbc5c9f016eb52145b320063" +dependencies = [ + "arrayvec 0.7.6", + "multi-stash", + "smallvec", + "spin 0.9.8", + "wasmi_collections 0.40.0", + "wasmi_core 0.40.0", + "wasmi_ir", + "wasmparser 0.221.3", +] + [[package]] name = "wasmi_arena" version = "0.4.1" @@ -26443,6 +26742,12 @@ dependencies = [ "string-interner", ] +[[package]] +name = "wasmi_collections" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e80d6b275b1c922021939d561574bf376613493ae2b61c6963b15db0e8813562" + [[package]] name = "wasmi_core" version = "0.13.0" @@ -26467,6 +26772,34 @@ dependencies = [ "paste", ] +[[package]] +name = "wasmi_core" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8c51482cc32d31c2c7ff211cd2bedd73c5bd057ba16a2ed0110e7a96097c33" +dependencies = [ + "downcast-rs", + "libm", +] + +[[package]] +name = "wasmi_ir" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e431a14c186db59212a88516788bd68ed51f87aa1e08d1df742522867b5289a" +dependencies = [ + "wasmi_core 0.40.0", +] + +[[package]] +name = "wasmparser" +version = "0.221.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "wasmparser" version = "0.235.0" @@ -26497,7 +26830,7 @@ checksum = "75aa8e9076de6b9544e6dab4badada518cca0bf4966d35b131bbd057aed8fa0a" dependencies = [ "anyhow", "termcolor", - "wasmparser", + "wasmparser 0.235.0", ] [[package]] @@ -26529,7 +26862,7 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasmparser", + "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-asm-macros", "wasmtime-internal-cache", @@ -26565,7 +26898,7 @@ dependencies = [ "smallvec", "target-lexicon", "wasm-encoder 0.235.0", - "wasmparser", + "wasmparser 0.235.0", "wasmprinter", ] @@ -26619,7 +26952,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser", + "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-math", "wasmtime-internal-versioned-export-macros", @@ -26703,7 +27036,7 @@ dependencies = [ "gimli 0.31.1", "object 0.36.7", "target-lexicon", - "wasmparser", + "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-cranelift", "winch-codegen", @@ -26993,7 +27326,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser", + "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-cranelift", "wasmtime-internal-math", @@ -27364,7 +27697,7 @@ dependencies = [ "data-encoding", "der-parser 9.0.0", "lazy_static", - "nom", + "nom 7.1.3", "oid-registry 0.7.0", "rusticata-macros", "thiserror 1.0.65", @@ -27381,7 +27714,7 @@ dependencies = [ "data-encoding", "der-parser 10.0.0", "lazy_static", - "nom", + "nom 7.1.3", "oid-registry 0.8.1", "rusticata-macros", "thiserror 2.0.12", @@ -27855,9 +28188,9 @@ dependencies = [ [[package]] name = "zombienet-configuration" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a6f9764e5f322f1aa44e1a75258adbabbe1b530974252a66e81331cfe805d5" +checksum = "a5e93ea881757b3d3015d9dd41e04ceafb4d9747c5edd36a3f772c3137cec142" dependencies = [ "anyhow", "lazy_static", @@ -27876,9 +28209,9 @@ dependencies = [ [[package]] name = "zombienet-orchestrator" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d7e28aafee53c025762afbc77ebb31b34ef81066bd967ed569508fc42057934" +checksum = "ce17e41af0ad18befadbd7fc2658d2e54e9f644f51b07b1cf68d58d50a3049b9" dependencies = [ "anyhow", "async-trait", @@ -27895,9 +28228,9 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "sp-core 35.0.0", - "subxt 0.38.1", - "subxt-signer 0.38.0", + "sp-core 36.1.0", + "subxt 0.43.0", + "subxt-signer 0.43.0", "thiserror 1.0.65", "tokio", "tracing", @@ -27910,9 +28243,9 @@ dependencies = [ [[package]] name = "zombienet-prom-metrics-parser" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a481e65f290606b358a2c9e79d8f945142a7414f38670113fff3453ac1604bc" +checksum = "fe24a05a4dda190039120ca480b729c5953f1aa52edc2caa1990b06281b71b93" dependencies = [ "pest", "pest_derive", @@ -27921,9 +28254,9 @@ dependencies = [ [[package]] name = "zombienet-provider" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b67d77160754d0681d289a123d11f2a0b23869a222536af046618c94bbb872" +checksum = "38f2f1e242017d86ed78edc0a89478e2e5b95ea22059ed3ca51bf6feb0992b82" dependencies = [ "anyhow", "async-trait", @@ -27952,15 +28285,15 @@ dependencies = [ [[package]] name = "zombienet-sdk" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91beaacd1c1e824d34b1ff8322834f0762cb5e38e3272611f43d8c1225e6b80c" +checksum = "0ee9678f47cb3e5d52a7c58a11ef4cfdfca33c2388cd755752732aadf563b1ee" dependencies = [ "async-trait", "futures", "lazy_static", - "subxt 0.38.1", - "subxt-signer 0.38.0", + "subxt 0.43.0", + "subxt-signer 0.43.0", "tokio", "zombienet-configuration", "zombienet-orchestrator", @@ -27970,9 +28303,9 @@ dependencies = [ [[package]] name = "zombienet-support" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ff14369c69535857b0a6889f7968032c37d51a43bdd3441a4b0bf060648943" +checksum = "a7e7adcfce4103f9caad531e337001163c5f56c844125fbd580a57dfe3e5463e" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index ea58a96bab296..ae54190d18a9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1474,9 +1474,9 @@ xcm-runtime-apis = { path = "polkadot/xcm/xcm-runtime-apis", default-features = xcm-simulator = { path = "polkadot/xcm/xcm-simulator", default-features = false } yet-another-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/yet-another-parachain" } zeroize = { version = "1.7.0", default-features = false } -zombienet-configuration = { version = "0.3.8" } -zombienet-orchestrator = { version = "0.3.8" } -zombienet-sdk = { version = "0.3.8" } +zombienet-configuration = { version = "0.3.12" } +zombienet-orchestrator = { version = "0.3.12" } +zombienet-sdk = { version = "0.3.12" } zstd = { version = "0.12.4", default-features = false } [profile.release] From 4132ad3152d0a23fab798f6a58715d4facb67f94 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 26 Aug 2025 12:02:20 +0200 Subject: [PATCH 02/16] resolve and merge --- Cargo.lock | 5955 ++++++++++------- Cargo.toml | 3 +- .../assets/asset-hub-westend/tests/tests.rs | 25 +- prdoc/pr_9501.prdoc | 13 + substrate/frame/revive/Cargo.toml | 2 + substrate/frame/revive/fixtures/Cargo.toml | 12 +- substrate/frame/revive/fixtures/build.rs | 250 +- .../revive/fixtures/contracts/dummy.polkavm | Bin 1726 -> 0 bytes .../frame/revive/fixtures/contracts/dummy.sol | 14 - .../revive/fixtures/contracts/fake_erc20.sol | 54 - .../{contracts => erc20}/erc20.polkavm | Bin .../fixtures/{contracts => erc20}/erc20.sol | 0 .../expensive_erc20.polkavm | Bin .../{contracts => erc20}/expensive_erc20.sol | 0 .../{contracts => erc20}/fake_erc20.polkavm | Bin substrate/frame/revive/fixtures/src/lib.rs | 37 +- substrate/frame/revive/src/benchmarking.rs | 56 +- substrate/frame/revive/src/call_builder.rs | 2 +- substrate/frame/revive/src/exec.rs | 37 +- substrate/frame/revive/src/exec/mock_ext.rs | 259 + substrate/frame/revive/src/exec/tests.rs | 4 + substrate/frame/revive/src/impl_fungibles.rs | 11 +- substrate/frame/revive/src/lib.rs | 46 +- substrate/frame/revive/src/tests.rs | 4886 +------------- substrate/frame/revive/src/tests/pvm.rs | 4892 ++++++++++++++ substrate/frame/revive/src/vm/mod.rs | 162 +- substrate/frame/revive/src/vm/pvm.rs | 960 +++ substrate/frame/revive/src/vm/pvm/env.rs | 1037 +++ substrate/frame/revive/src/vm/runtime.rs | 2111 ------ .../frame/revive/src/vm/runtime_costs.rs | 315 + substrate/primitives/runtime/Cargo.toml | 1 + 31 files changed, 11298 insertions(+), 9846 deletions(-) create mode 100644 prdoc/pr_9501.prdoc delete mode 100644 substrate/frame/revive/fixtures/contracts/dummy.polkavm delete mode 100644 substrate/frame/revive/fixtures/contracts/dummy.sol delete mode 100644 substrate/frame/revive/fixtures/contracts/fake_erc20.sol rename substrate/frame/revive/fixtures/{contracts => erc20}/erc20.polkavm (100%) rename substrate/frame/revive/fixtures/{contracts => erc20}/erc20.sol (100%) rename substrate/frame/revive/fixtures/{contracts => erc20}/expensive_erc20.polkavm (100%) rename substrate/frame/revive/fixtures/{contracts => erc20}/expensive_erc20.sol (100%) rename substrate/frame/revive/fixtures/{contracts => erc20}/fake_erc20.polkavm (100%) create mode 100644 substrate/frame/revive/src/exec/mock_ext.rs create mode 100644 substrate/frame/revive/src/tests/pvm.rs create mode 100644 substrate/frame/revive/src/vm/pvm.rs create mode 100644 substrate/frame/revive/src/vm/pvm/env.rs delete mode 100644 substrate/frame/revive/src/vm/runtime.rs create mode 100644 substrate/frame/revive/src/vm/runtime_costs.rs diff --git a/Cargo.lock b/Cargo.lock index ae3e8df895111..9da0fa0359f25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,29 +12,20 @@ dependencies = [ "regex", ] -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli 0.28.0", -] - [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.31.1", + "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adler32" @@ -54,9 +45,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher 0.4.4", @@ -74,27 +65,27 @@ dependencies = [ "cipher 0.4.4", "ctr", "ghash", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.10", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.32", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -107,9 +98,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-core" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c5a28f166629752f2e7246b813cdea3243cca59aab2d4264b1fd68392c10eb" +checksum = "bfe6c56d58fbfa9f0f6299376e8ce33091fc6494239466814c3f54b55743cb09" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -120,9 +111,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6" +checksum = "a3f56873f3cac7a2c63d8e98a4314b8311aa96adb1a0f82ae923eb2119809d2c" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -131,14 +122,71 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.7.10", + "winnow 0.7.13", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror 2.0.16", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "k256", + "serde", + "thiserror 2.0.16", +] + +[[package]] +name = "alloy-eips" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab489a99806d6586118b4712506e56c2888cdf4798f29b401511bc3af13475" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "c-kzg", + "derive_more 2.0.1", + "either", + "serde", + "sha2 0.10.9", ] [[package]] name = "alloy-json-abi" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" +checksum = "125a1c373261b252e53e04d6e92c37d881833afc1315fceab53fd46045695640" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -148,24 +196,24 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8" +checksum = "bc9485c56de23438127a731a6b4c87803d49faf1a7068dcd1d8768aca3a9edb9" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more 2.0.1", - "foldhash", - "hashbrown 0.15.3", + "foldhash 0.1.5", + "hashbrown 0.15.5", "indexmap", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.9.0", + "rand 0.9.2", "ruint", "rustc-hash 2.1.1", "serde", @@ -175,78 +223,100 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.3" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ + "alloy-rlp-derive", "arrayvec 0.7.6", "bytes", - "smol_str", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" +dependencies = [ + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.106", +] + +[[package]] +name = "alloy-serde" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93cb27da33b618fe729ab6b053275e754fbb31782caa83dfd11219d7e2e8ebf1" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", ] [[package]] name = "alloy-sol-macro" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383" +checksum = "d20d867dcf42019d4779519a1ceb55eba8d7f3d0e4f0a89bcba82b8f9eb01e48" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74" +checksum = "b74e91b0b553c115d14bd0ed41898309356dc85d0e3d4b9014c4e7715e48c8ad" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", "indexmap", "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5" +checksum = "84194d31220803f5f62d0a00f583fd3a062b36382e2bea446f1af96727754565" dependencies = [ "const-hex", "dunce", "heck 0.5.0", "macro-string", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837" +checksum = "fe8c27b3cf6b2bb8361904732f955bc7c05e00be5f469cec7e2280b6167f3ff0" dependencies = [ "serde", - "winnow 0.7.10", + "winnow 0.7.13", ] [[package]] name = "alloy-sol-types" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" +checksum = "f5383d34ea00079e6dd89c652bcbdb764db160cef84e6250926961a0b2295d04" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -283,57 +353,59 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "approx" @@ -353,16 +425,16 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] @@ -428,6 +500,18 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + [[package]] name = "ark-bw6-761" version = "0.4.0" @@ -484,7 +568,7 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "itertools 0.13.0", "num-bigint", "num-integer", @@ -589,7 +673,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -641,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -664,7 +748,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -677,9 +761,9 @@ checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -720,10 +804,39 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "rayon", ] +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-scale" version = "0.0.12" @@ -792,7 +905,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -803,9 +916,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -869,31 +982,32 @@ dependencies = [ "digest 0.10.7", "rand_chacha 0.3.1", "rayon", - "sha2 0.10.8", + "sha2 0.10.9", "w3f-ring-proof", "zeroize", ] [[package]] name = "array-bytes" -version = "6.2.2" +version = "6.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" +checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293" [[package]] name = "array-bytes" -version = "9.1.2" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4449507daf4f07a8c8309e122d32a53d15c9f33e77eaf01c839fea42ccd4d673" +checksum = "27d55334c98d756b32dcceb60248647ab34f027690f87f9a362fd292676ee927" dependencies = [ "smallvec", + "thiserror 2.0.16", ] [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -912,25 +1026,25 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ - "asn1-rs-derive 0.5.0", + "asn1-rs-derive 0.5.1", "asn1-rs-impl", "displaydoc", "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 1.0.65", + "thiserror 1.0.69", "time", ] [[package]] name = "asn1-rs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607495ec7113b178fbba7a6166a27f99e774359ef4823adbefd756b5b81d7970" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" dependencies = [ "asn1-rs-derive 0.6.0", "asn1-rs-impl", @@ -938,20 +1052,20 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "synstructure 0.13.1", + "syn 2.0.106", + "synstructure 0.13.2", ] [[package]] @@ -960,10 +1074,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "synstructure 0.13.1", + "syn 2.0.106", + "synstructure 0.13.2", ] [[package]] @@ -972,20 +1086,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "assert_cmd" -version = "2.0.14" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" +checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66" dependencies = [ "anstyle", "bstr", "doc-comment", + "libc", "predicates", "predicates-core", "predicates-tree", @@ -1377,12 +1492,11 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", - "event-listener 5.3.1", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -1390,15 +1504,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.5.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" dependencies = [ - "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand 1.9.0", - "futures-lite 1.13.0", + "fastrand 2.3.0", + "futures-lite 2.6.1", + "pin-project-lite", "slab", ] @@ -1416,27 +1530,27 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" dependencies = [ - "async-lock 3.4.0", + "async-lock 3.4.1", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.6.1", ] [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 1.9.0", + "async-channel 2.5.0", "async-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io 2.5.0", + "async-lock 3.4.1", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.6.1", "once_cell", ] @@ -1454,29 +1568,28 @@ dependencies = [ "log", "parking", "polling 2.8.0", - "rustix 0.37.23", + "rustix 0.37.28", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] [[package]] name = "async-io" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" dependencies = [ - "async-lock 3.4.0", + "async-lock 3.4.1", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "parking", - "polling 3.4.0", - "rustix 0.38.42", + "polling 3.10.0", + "rustix 1.0.8", "slab", - "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -1490,23 +1603,22 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-net" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" +checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" dependencies = [ "async-io 1.13.0", - "autocfg", "blocking", "futures-lite 1.13.0", ] @@ -1517,83 +1629,81 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.3.3", + "async-io 2.5.0", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.6.1", ] [[package]] name = "async-process" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", - "autocfg", + "async-signal", "blocking", "cfg-if", - "event-listener 2.5.3", + "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.37.23", - "signal-hook", + "rustix 0.38.44", "windows-sys 0.48.0", ] [[package]] name = "async-process" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" dependencies = [ - "async-channel 2.3.0", - "async-io 2.3.3", - "async-lock 3.4.0", + "async-channel 2.5.0", + "async-io 2.5.0", + "async-lock 3.4.1", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.3.1", - "futures-lite 2.3.0", - "rustix 0.38.42", - "tracing", + "event-listener 5.4.1", + "futures-lite 2.6.1", + "rustix 1.0.8", ] [[package]] name = "async-signal" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" dependencies = [ - "async-io 2.3.3", - "async-lock 3.4.0", + "async-io 2.5.0", + "async-lock 3.4.1", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.42", + "rustix 1.0.8", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io 2.5.0", + "async-lock 3.4.1", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", - "gloo-timers", + "futures-lite 2.6.1", + "gloo-timers 0.3.0", "kv-log-macro", "log", "memchr", @@ -1606,9 +1716,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -1617,13 +1727,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -1634,13 +1744,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -1686,9 +1796,9 @@ checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attohttpc" @@ -1696,28 +1806,37 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" dependencies = [ - "http 0.2.9", + "http 0.2.12", "log", "url", ] +[[package]] +name = "aurora-engine-modexp" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518bc5745a6264b5fd7b09dffb9667e400ee9e2bbe18555fac75e1fe9afa0df9" +dependencies = [ + "hex", + "num", +] + [[package]] name = "auto_impl" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "average" @@ -1730,30 +1849,36 @@ dependencies = [ "num-traits", ] +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "backoff" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.16", "instant", "rand 0.8.5", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ - "addr2line 0.21.0", - "cc", + "addr2line", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1794,15 +1919,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "binary-merkle-tree" version = "13.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "hash-db", "log", "parity-scale-codec", @@ -1832,35 +1957,36 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "bip32" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" dependencies = [ "bs58", "hmac 0.12.1", "k256", "rand_core 0.6.4", "ripemd", - "sha2 0.10.8", - "subtle 2.5.0", + "secp256k1 0.27.0", + "sha2 0.10.9", + "subtle 2.6.1", "zeroize", ] [[package]] name = "bip39" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" +checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" dependencies = [ "bitcoin_hashes 0.13.0", "serde", @@ -1901,7 +2027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals", - "hex-conservative 0.1.1", + "hex-conservative 0.1.2", ] [[package]] @@ -1922,9 +2048,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" dependencies = [ "serde", ] @@ -1975,37 +2101,37 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" dependencies = [ "arrayref", "arrayvec 0.7.6", - "constant_time_eq 0.3.0", + "constant_time_eq 0.3.1", ] [[package]] name = "blake2s_simd" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +checksum = "e90f7deecfac93095eb874a40febd69427776e24e1bd7f87f33ac62d6f0174df" dependencies = [ "arrayref", "arrayvec 0.7.6", - "constant_time_eq 0.2.6", + "constant_time_eq 0.3.1", ] [[package]] name = "blake3" -version = "1.5.4" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec 0.7.6", "cc", "cfg-if", - "constant_time_eq 0.3.0", + "constant_time_eq 0.3.1", ] [[package]] @@ -2028,17 +2154,27 @@ dependencies = [ [[package]] name = "blocking" -version = "1.3.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 1.9.0", - "async-lock 2.8.0", + "async-channel 2.5.0", "async-task", - "atomic-waker", - "fastrand 1.9.0", - "futures-lite 1.13.0", - "log", + "futures-io", + "futures-lite 2.6.1", + "piper", +] + +[[package]] +name = "blst" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] @@ -2055,9 +2191,9 @@ dependencies = [ [[package]] name = "bounded-collections" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ed0a820ed50891d36358e997d27741a6142e382242df40ff01c89bcdcc7a2b" +checksum = "64ad8a0bed7827f0b07a5d23cec2e58cc02038a99e4ca81616cb2bb2025f804d" dependencies = [ "log", "parity-scale-codec", @@ -2075,7 +2211,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "schemars", + "schemars 1.0.4", "serde", ] @@ -2085,7 +2221,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68534a48cbf63a4b1323c433cf21238c9ec23711e0df13b08c33e5c2082663ce" dependencies = [ - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -2797,18 +2933,18 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2 0.10.8", + "sha2 0.10.9", "tinyvec", ] [[package]] name = "bstr" -version = "1.6.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", - "regex-automata 0.3.6", + "regex-automata 0.4.10", "serde", ] @@ -2844,9 +2980,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" [[package]] name = "byteorder" @@ -2865,15 +3001,29 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ "cc", - "libc", "pkg-config", ] +[[package]] +name = "c-kzg" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + [[package]] name = "c2-chacha" version = "0.3.3" @@ -2886,18 +3036,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -2910,10 +3060,10 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.18", + "semver 1.0.26", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -2930,9 +3080,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.1.24" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "jobserver", "libc", @@ -2956,18 +3106,18 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -3038,9 +3188,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -3053,9 +3203,9 @@ dependencies = [ [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -3064,15 +3214,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -3099,7 +3249,7 @@ checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" dependencies = [ "core2", "multibase", - "multihash 0.19.1", + "multihash 0.19.3", "unsigned-varint 0.8.0", ] @@ -3125,9 +3275,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -3136,9 +3286,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", "clap_derive", @@ -3146,9 +3296,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstream", "anstyle", @@ -3159,39 +3309,39 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.13" +version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa3c596da3cf0983427b0df0dba359df9182c13bd5b519b585a482b0c351f4e8" +checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmd_lib" -version = "1.9.5" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "371c15a3c178d0117091bd84414545309ca979555b1aad573ef591ad58818d41" +checksum = "1af0f9b65935ff457da75535a6b6ff117ac858f03f71191188b3b696f90aec5a" dependencies = [ "cmd_lib_macros", - "env_logger 0.10.1", + "env_logger 0.10.2", "faccess", "lazy_static", "log", @@ -3200,25 +3350,24 @@ dependencies = [ [[package]] name = "cmd_lib_macros" -version = "1.9.5" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb844bd05be34d91eb67101329aeba9d3337094c04fd8507d821db7ebb488eaf" +checksum = "1e69eee115667ccda8b9ed7010bcf13356ad45269fc92aa78534890b42809a64" dependencies = [ "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "coarsetime" -version = "0.1.23" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" +checksum = "91849686042de1b41cd81490edc83afbcb0abe5a9b6f2c4114f23ce8cca1bcf4" dependencies = [ "libc", - "once_cell", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasix", "wasm-bindgen", ] @@ -3228,17 +3377,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "codespan-reporting" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ + "serde", "termcolor", - "unicode-width 0.1.10", + "unicode-width", ] [[package]] @@ -3362,9 +3512,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" dependencies = [ "backtrace", "eyre", @@ -3375,47 +3525,46 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom 7.1.3", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" -version = "2.0.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ - "is-terminal", "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -3428,7 +3577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" dependencies = [ "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -3448,22 +3597,22 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width 0.1.10", - "windows-sys 0.52.0", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", ] [[package]] name = "const-hex" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" +checksum = "dccd746bf9b1038c0507b7cec21eb2b11222db96a2902c96e8c185d6d20fb9c4" dependencies = [ "cfg-if", "cpufeatures", @@ -3474,29 +3623,27 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-random" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", - "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.16", "once_cell", - "proc-macro-hack", "tiny-keccak", ] @@ -3515,9 +3662,9 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] @@ -3528,15 +3675,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" - -[[package]] -name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -3563,11 +3704,21 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -3777,9 +3928,9 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] @@ -3796,9 +3947,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -3855,8 +4006,8 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli 0.31.1", - "hashbrown 0.15.3", + "gimli", + "hashbrown 0.15.5", "log", "pulley-interpreter", "regalloc2 0.12.2", @@ -3942,9 +4093,9 @@ checksum = "b530783809a55cb68d070e0de60cfbb3db0dc94c8850dd5725411422bedcf6bb" [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -3957,9 +4108,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -4019,58 +4170,53 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -4102,7 +4248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -4116,7 +4262,7 @@ dependencies = [ "generic-array 0.14.7", "poly1305", "salsa20", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -4131,11 +4277,11 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ - "nix 0.29.0", + "nix 0.30.1", "windows-sys 0.59.0", ] @@ -4143,7 +4289,7 @@ dependencies = [ name = "cumulus-client-bootnodes" version = "0.1.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -4192,7 +4338,7 @@ dependencies = [ "cumulus-test-runtime", "futures", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -4225,7 +4371,7 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "futures", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-util", @@ -4312,7 +4458,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -4324,7 +4470,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-consensus", "sp-api", "sp-block-builder", @@ -4349,7 +4495,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-parachain-primitives", @@ -4521,7 +4667,7 @@ dependencies = [ "frame-support", "frame-system", "futures", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "hex-literal", "impl-trait-for-tuples", "log", @@ -4558,10 +4704,10 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -4679,7 +4825,7 @@ dependencies = [ "sp-io", "sp-maybe-compressed-blob", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4821,14 +4967,14 @@ dependencies = [ "sp-blockchain", "sp-state-machine", "sp-version", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "cumulus-relay-chain-minimal-node" version = "0.7.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "async-trait", "cumulus-client-bootnodes", @@ -4893,7 +5039,7 @@ dependencies = [ "sp-storage 19.0.0", "sp-version", "substrate-prometheus-endpoint", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -5100,7 +5246,7 @@ version = "0.1.0" dependencies = [ "anyhow", "cumulus-zombienet-sdk-helpers", - "env_logger 0.11.3", + "env_logger 0.11.8", "futures", "log", "polkadot-primitives", @@ -5117,24 +5263,24 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.46" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "79fc3b6dd0b87ba36e565715bf9a2ced221311db47bd18011676f24a6066edbc" dependencies = [ "curl-sys", "libc", "openssl-probe", "openssl-sys", "schannel", - "socket2 0.5.9", - "windows-sys 0.52.0", + "socket2 0.6.0", + "windows-sys 0.59.0", ] [[package]] name = "curl-sys" -version = "0.4.72+curl-8.6.0" +version = "0.4.83+curl-8.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "5830daf304027db10c82632a464879d46a3f7c4ba17a31592657ad16c719b483" dependencies = [ "cc", "libc", @@ -5143,7 +5289,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5157,20 +5303,20 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", - "subtle 2.5.0", + "rustc_version 0.4.1", + "subtle 2.6.1", "zeroize", ] [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -5188,53 +5334,71 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.106" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" +checksum = "df881e2764e20d320c9c8ddd8670018b1abaa2557e73811f03d5b2643da671d7" dependencies = [ "cc", + "cxxbridge-cmd", "cxxbridge-flags", "cxxbridge-macro", + "foldhash 0.2.0", "link-cplusplus", ] [[package]] name = "cxx-build" -version = "1.0.106" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" +checksum = "acef58f684c0c9b7bffc111657c9f1364e4fa47af46fd7f03b71b7a4066ac372" dependencies = [ "cc", "codespan-reporting", - "once_cell", - "proc-macro2 1.0.95", + "indexmap", + "proc-macro2 1.0.101", "quote 1.0.40", "scratch", - "syn 2.0.98", + "syn 2.0.106", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669616995d33251cb7215f96820d78a810ee218573246830fb96f29961e1712a" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.106", ] [[package]] name = "cxxbridge-flags" -version = "1.0.106" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" +checksum = "9aebcb754a24722d34e7f4e021376862179194cc5ec83ded2dd84b9db36be106" [[package]] name = "cxxbridge-macro" -version = "1.0.106" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" +checksum = "3ea9594efbebf2f822925b6368eea741dd2677bb411313e50c2de8ba8c3d3a62" dependencies = [ - "proc-macro2 1.0.95", + "indexmap", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "rustversion", + "syn 2.0.106", ] [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -5242,53 +5406,53 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "strsim", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.11", ] [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -5296,12 +5460,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] @@ -5315,9 +5479,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -5330,7 +5494,7 @@ version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", "displaydoc", "nom 7.1.3", "num-bigint", @@ -5344,7 +5508,7 @@ version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ - "asn1-rs 0.7.0", + "asn1-rs 0.7.1", "displaydoc", "nom 7.1.3", "num-bigint", @@ -5354,9 +5518,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -5367,7 +5531,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -5378,44 +5542,44 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "derive-where" -version = "1.2.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "rustc_version 0.4.0", - "syn 1.0.109", + "rustc_version 0.4.1", + "syn 2.0.106", ] [[package]] @@ -5442,10 +5606,10 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "unicode-xid 0.2.4", + "syn 2.0.106", + "unicode-xid 0.2.6", ] [[package]] @@ -5455,10 +5619,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "convert_case 0.7.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "unicode-xid 0.2.4", + "syn 2.0.106", + "unicode-xid 0.2.6", ] [[package]] @@ -5500,7 +5664,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -5556,28 +5720,30 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "dissimilar" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" [[package]] name = "dlmalloc" -version = "0.2.4" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" +checksum = "06cdfe340b16dd990c54cce79743613fa09fbb16774f33a77c9fd196f8f3fa30" dependencies = [ + "cfg-if", "libc", + "windows-sys 0.60.2", ] [[package]] @@ -5604,12 +5770,12 @@ dependencies = [ "common-path", "derive-syn-parse", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", - "syn 2.0.98", + "syn 2.0.106", "termcolor", - "toml", + "toml 0.8.23", "walkdir", ] @@ -5627,9 +5793,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "drawille" @@ -5643,21 +5809,21 @@ dependencies = [ [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clonable" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +checksum = "a36efbb9bfd58e1723780aa04b61aba95ace6a05d9ffabfdb0b43672552f0805" dependencies = [ "dyn-clonable-impl", "dyn-clone", @@ -5665,20 +5831,20 @@ dependencies = [ [[package]] name = "dyn-clonable-impl" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +checksum = "7e8671d54058979a37a26f3511fbf8d198ba1aa35ffb202c42587d918d77213a" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "easy-cast" @@ -5691,9 +5857,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", @@ -5706,9 +5872,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", @@ -5716,31 +5882,32 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", "rand_core 0.6.4", "serde", - "sha2 0.10.8", - "subtle 2.5.0", + "sha2 0.10.9", + "subtle 2.6.1", "zeroize", ] [[package]] name = "ed25519-zebra" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +checksum = "0017d969298eec91e3db7a2985a8cab4df6341d86e6f3a6f5878b13fb7846bc9" dependencies = [ "curve25519-dalek", "ed25519", - "hashbrown 0.14.5", - "hex", + "hashbrown 0.15.5", + "pkcs8", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.9", + "subtle 2.6.1", "zeroize", ] @@ -5751,16 +5918,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ "serde", ] @@ -5781,7 +5948,7 @@ dependencies = [ "rand_core 0.6.4", "sec1", "serdect", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -5841,29 +6008,29 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.95", + "heck 0.5.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -5881,40 +6048,40 @@ version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "enumn" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -5939,9 +6106,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -5952,14 +6119,14 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] @@ -5971,9 +6138,9 @@ checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "equivocation-detector" @@ -5991,11 +6158,12 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", + "typeid", ] [[package]] @@ -6010,12 +6178,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -6085,9 +6253,20 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.3.1" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -6096,11 +6275,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "pin-project-lite", ] @@ -6123,16 +6302,16 @@ dependencies = [ "file-guard", "fs-err", "prettyplease", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -6162,8 +6341,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", + "regex-automata 0.4.10", + "regex-syntax 0.8.6", ] [[package]] @@ -6210,7 +6389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec6f82451ff7f0568c6181287189126d492b5654e30a788add08027b6363d019" dependencies = [ "fatality-proc-macro", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -6221,10 +6400,10 @@ checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", "indexmap", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -6234,7 +6413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5" dependencies = [ "libc", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -6255,19 +6434,19 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file-guard" @@ -6281,14 +6460,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "libredox", + "windows-sys 0.60.2", ] [[package]] @@ -6303,7 +6482,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "scale-info", ] @@ -6319,7 +6498,7 @@ dependencies = [ "futures", "log", "num-traits", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "relay-utils", ] @@ -6363,11 +6542,17 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" -version = "1.0.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -6402,6 +6587,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -6426,9 +6617,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -6440,7 +6631,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" dependencies = [ "nonempty", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -6455,15 +6646,15 @@ dependencies = [ [[package]] name = "fragile" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" [[package]] name = "frame-benchmarking" version = "28.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-support", "frame-support-procedural", "frame-system", @@ -6493,7 +6684,7 @@ name = "frame-benchmarking-cli" version = "32.0.0" dependencies = [ "Inflector", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "chrono", "clap", "comfy-table", @@ -6550,7 +6741,7 @@ dependencies = [ "substrate-test-runtime", "subxt 0.41.0", "subxt-signer 0.41.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "thousands", "westend-runtime", ] @@ -6588,7 +6779,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7cb8796f93fa038f979a014234d632e9688a120e745f936e2635123c77537f7" dependencies = [ - "frame-metadata 20.0.0", + "frame-metadata 21.0.0", "parity-scale-codec", "scale-decode 0.16.0", "scale-info", @@ -6617,12 +6808,12 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "sp-arithmetic", - "syn 2.0.98", + "syn 2.0.106", "trybuild", ] @@ -6662,7 +6853,7 @@ name = "frame-executive" version = "28.0.0" dependencies = [ "aquamarine", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-support", "frame-system", "frame-try-runtime", @@ -6704,6 +6895,17 @@ dependencies = [ "serde", ] +[[package]] +name = "frame-metadata" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20dfd1d7eae1d94e32e869e2fb272d81f52dd8db57820a373adb83ea24d7d862" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "frame-metadata" version = "23.0.0" @@ -6720,7 +6922,7 @@ dependencies = [ name = "frame-metadata-hash-extension" version = "0.1.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "const-hex", "docify", "frame-metadata 23.0.0", @@ -6753,7 +6955,7 @@ dependencies = [ "sp-runtime", "sp-statement-store", "tempfile", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -6797,7 +6999,7 @@ version = "28.0.0" dependencies = [ "Inflector", "aquamarine", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "binary-merkle-tree", "bitflags 1.3.2", "docify", @@ -6854,7 +7056,7 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "proc-macro-warning", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "scale-info", @@ -6862,7 +7064,7 @@ dependencies = [ "sp-io", "sp-metadata-ir", "sp-runtime", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -6870,19 +7072,19 @@ name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -7004,9 +7206,12 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fs2" @@ -7024,7 +7229,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.42", + "rustix 0.38.44", "windows-sys 0.48.0", ] @@ -7101,7 +7306,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -7127,9 +7332,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand 2.3.0", "futures-core", @@ -7144,9 +7349,9 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -7156,7 +7361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.18", + "rustls 0.23.31", "rustls-pki-types", ] @@ -7178,7 +7383,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers", + "gloo-timers 0.2.6", "send_wrapper", ] @@ -7215,15 +7420,16 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" dependencies = [ + "cc", "cfg-if", "libc", "log", "rustversion", - "windows 0.58.0", + "windows 0.61.3", ] [[package]] @@ -7258,25 +7464,29 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -7291,20 +7501,14 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "polyval", ] -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - [[package]] name = "gimli" version = "0.31.1" @@ -7318,11 +7522,11 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "libc", "libgit2-sys", "log", @@ -7331,9 +7535,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "glob-match" @@ -7351,12 +7555,12 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.1.0", + "http 1.3.1", "js-sys", "pin-project", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -7374,6 +7578,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "gloo-utils" version = "0.2.0" @@ -7433,6 +7649,16 @@ dependencies = [ "testnet-parachains-constants", ] +[[package]] +name = "gmp-mpfr-sys" +version = "1.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a636fb6a653382a379ee1e5593dacdc628667994167024c143214cafd40c1a86" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "governance-westend-integration-tests" version = "0.0.0" @@ -7455,9 +7681,9 @@ dependencies = [ [[package]] name = "governor" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ "cfg-if", "dashmap", @@ -7465,10 +7691,12 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.3", + "parking_lot 0.12.4", + "portable-atomic", "quanta", "rand 0.8.5", "smallvec", + "spinning_top", ] [[package]] @@ -7479,21 +7707,21 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.9", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -7503,16 +7731,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http 1.3.1", "indexmap", "slab", "tokio", @@ -7522,22 +7750,26 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "handlebars" -version = "5.1.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", "pest_derive", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -7577,13 +7809,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -7598,11 +7830,11 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.5", ] [[package]] @@ -7623,6 +7855,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -7634,9 +7872,9 @@ dependencies = [ [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex-conservative" @@ -7655,9 +7893,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ "async-trait", "cfg-if", @@ -7666,12 +7904,12 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna", "ipnet", "once_cell", "rand 0.8.5", - "socket2 0.5.9", - "thiserror 1.0.65", + "socket2 0.5.10", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -7691,12 +7929,12 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 1.0.3", + "idna", "ipnet", "once_cell", - "rand 0.9.0", - "ring 0.17.8", - "thiserror 2.0.12", + "rand 0.9.2", + "ring 0.17.14", + "thiserror 2.0.16", "tinyvec", "tokio", "tracing", @@ -7705,21 +7943,21 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.2" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" dependencies = [ "cfg-if", "futures-util", - "hickory-proto 0.24.1", + "hickory-proto 0.24.4", "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "resolv-conf", "smallvec", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -7736,11 +7974,11 @@ dependencies = [ "ipconfig", "moka", "once_cell", - "parking_lot 0.12.3", - "rand 0.9.0", + "parking_lot 0.12.4", + "rand 0.9.2", "resolv-conf", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -7786,41 +8024,31 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "honggfuzz" -version = "0.5.55" +version = "0.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +checksum = "fc563d4f41b17364d5c48ded509f2bcf1c3f6ae9c7f203055b4a5c325072d57e" dependencies = [ "arbitrary", "lazy_static", - "memmap2 0.5.10", - "rustc_version 0.4.0", -] - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", + "memmap2 0.9.8", + "rustc_version 0.4.1", + "semver 1.0.26", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -7829,9 +8057,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -7840,35 +8068,35 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.9", + "http 0.2.12", "pin-project-lite", ] [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] @@ -7880,9 +8108,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -7892,9 +8120,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "humantime-serde" @@ -7908,22 +8136,22 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.9", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -7932,20 +8160,22 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "futures-core", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", "httparse", "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -7958,10 +8188,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.9", - "hyper 0.14.29", + "http 0.2.12", + "hyper 0.14.32", "log", - "rustls 0.21.7", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -7969,22 +8199,21 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http 1.1.0", - "hyper 1.6.0", + "http 1.3.1", + "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.18", - "rustls-native-certs 0.8.0", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 0.26.3", + "webpki-roots 1.0.2", ] [[package]] @@ -7993,7 +8222,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.29", + "hyper 0.14.32", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -8007,7 +8236,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "native-tls", "tokio", @@ -8017,35 +8246,43 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.6.0", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", - "socket2 0.5.9", + "socket2 0.6.0", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows 0.48.0", + "windows-core 0.61.2", ] [[package]] @@ -8059,21 +8296,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -8082,31 +8320,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -8114,67 +8332,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2 1.0.95", - "quote 1.0.40", - "syn 2.0.98", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -8183,19 +8388,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -8204,9 +8399,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -8224,21 +8419,25 @@ dependencies = [ [[package]] name = "if-watch" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" dependencies = [ - "async-io 2.3.3", - "core-foundation", + "async-io 2.5.0", + "core-foundation 0.9.4", "fnv", "futures", "if-addrs", "ipnet", "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", "rtnetlink", - "system-configuration 0.5.1", + "system-configuration", "tokio", - "windows 0.51.1", + "windows 0.53.0", ] [[package]] @@ -8251,8 +8450,8 @@ dependencies = [ "attohttpc", "bytes", "futures", - "http 0.2.9", - "hyper 0.14.29", + "http 0.2.12", + "hyper 0.14.32", "log", "rand 0.8.5", "tokio", @@ -8313,44 +8512,44 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "include_dir" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", ] [[package]] name = "indenter" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "serde", ] @@ -8362,22 +8561,22 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width 0.1.10", + "unicode-width", + "web-time", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array 0.14.7", ] @@ -8406,11 +8605,22 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.3", + "cfg-if", + "libc", +] + [[package]] name = "ip_network" version = "0.4.1" @@ -8423,7 +8633,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.9", + "socket2 0.5.10", "widestring", "windows-sys 0.48.0", "winreg", @@ -8431,30 +8641,46 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi", - "rustix 0.38.42", - "windows-sys 0.48.0", + "hermit-abi 0.5.2", + "libc", + "windows-sys 0.59.0", ] [[package]] name = "is_executable" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4" dependencies = [ - "winapi", + "windows-sys 0.60.2", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "isahc" version = "1.7.2" @@ -8469,7 +8695,7 @@ dependencies = [ "encoding_rs", "event-listener 2.5.3", "futures-lite 1.13.0", - "http 0.2.9", + "http 0.2.12", "log", "mime", "once_cell", @@ -8529,15 +8755,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jam-codec" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d72f2fb8cfd27f6c52ea7d0528df594f7f2ed006feac153e9393ec567aafea98" +checksum = "cb948eace373d99de60501a02fb17125d30ac632570de20dccc74370cdd611b9" dependencies = [ "arrayvec 0.7.6", "bitvec", @@ -8551,28 +8777,54 @@ dependencies = [ [[package]] name = "jam-codec-derive" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319af585c4c8a6b5552a52b7787a1ab3e4d59df7614190b1f85b9b842488789d" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.106", +] + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09985146f40378e13af626964ac9c206d9d9b67c40c70805898d9954f709bcf5" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", - "thiserror 1.0.65", + "thiserror 1.0.69", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -8583,19 +8835,21 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -8607,7 +8861,7 @@ checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" dependencies = [ "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -8620,7 +8874,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -8636,9 +8890,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8" +checksum = "37b26c20e2178756451cfeb0661fb74c47dd5988cb7e3939de7e9241fd604d42" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -8654,24 +8908,24 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" +checksum = "bacb85abf4117092455e1573625e21b8f8ef4dec8aff13361140b2dc266cdff2" dependencies = [ "base64 0.22.1", "futures-channel", "futures-util", "gloo-net", - "http 1.1.0", + "http 1.3.1", "jsonrpsee-core", "pin-project", - "rustls 0.23.18", + "rustls 0.23.31", "rustls-pki-types", "rustls-platform-verifier", - "soketto 0.8.0", - "thiserror 1.0.65", + "soketto 0.8.1", + "thiserror 1.0.69", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.2", "tokio-util", "tracing", "url", @@ -8679,25 +8933,25 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" +checksum = "456196007ca3a14db478346f58c7238028d55ee15c1df15115596e411ff27925" dependencies = [ "async-trait", "bytes", "futures-timer", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", "jsonrpsee-types", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "rustc-hash 2.1.1", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8706,53 +8960,53 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" +checksum = "c872b6c9961a4ccc543e321bb5b89f6b2d2c7fe8b61906918273a3333c95400c" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.0", - "hyper 1.6.0", - "hyper-rustls 0.27.3", + "http-body 1.0.1", + "hyper 1.7.0", + "hyper-rustls 0.27.7", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.18", + "rustls 0.23.31", "rustls-platform-verifier", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" +checksum = "5e65763c942dfc9358146571911b0cd1c361c2d63e2d2305622d40d36376ca80" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "jsonrpsee-server" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" +checksum = "55e363146da18e50ad2b51a0a7925fc423137a0b1371af8235b1c231a0647328" dependencies = [ "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -8760,32 +9014,32 @@ dependencies = [ "route-recognizer", "serde", "serde_json", - "soketto 0.8.0", - "thiserror 1.0.65", + "soketto 0.8.1", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "jsonrpsee-types" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" +checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" dependencies = [ - "http 1.1.0", + "http 1.3.1", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" +checksum = "e6558a9586cad43019dafd0b6311d0938f46efc116b34b28c74778bc11a2edf6" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -8794,11 +9048,11 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" +checksum = "01b3323d890aa384f12148e8d2a1fd18eb66e9e7e825f9de4fa53bcc19b93eef" dependencies = [ - "http 1.1.0", + "http 1.3.1", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -8816,7 +9070,7 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -8835,9 +9089,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -8883,7 +9137,7 @@ checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" name = "kitchensink-runtime" version = "3.0.0-dev" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "log", "node-primitives", "pallet-example-mbm", @@ -8922,9 +9176,9 @@ dependencies = [ "either", "futures", "home", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.29", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", "hyper-rustls 0.24.2", "hyper-timeout", "jsonpath-rust", @@ -8933,17 +9187,17 @@ dependencies = [ "pem", "pin-project", "rand 0.8.5", - "rustls 0.21.7", - "rustls-pemfile 1.0.3", + "rustls 0.21.12", + "rustls-pemfile", "secrecy 0.8.0", "serde", "serde_json", "serde_yaml", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-tungstenite 0.20.1", "tokio-util", - "tower", + "tower 0.4.13", "tower-http 0.4.4", "tracing", ] @@ -8956,13 +9210,13 @@ checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae" dependencies = [ "chrono", "form_urlencoded", - "http 0.2.9", + "http 0.2.12", "json-patch", "k8s-openapi", "once_cell", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -8980,12 +9234,12 @@ dependencies = [ "json-patch", "k8s-openapi", "kube-client", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "serde", "serde_json", "smallvec", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -9016,7 +9270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -9027,7 +9281,7 @@ checksum = "b644c70b92285f66bfc2032922a79000ea30af7bc2ab31902992a5dcb9b434f6" dependencies = [ "kvdb", "num_cpus", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "regex", "rocksdb", "smallvec", @@ -9044,13 +9298,13 @@ dependencies = [ [[package]] name = "landlock" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc" +checksum = "9baa9eeb6e315942429397e617a190f4fdc696ef1ee0342939d641029cbb4ea7" dependencies = [ "enumflags2", "libc", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -9068,12 +9322,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -9082,9 +9330,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libflate" @@ -9108,20 +9356,19 @@ dependencies = [ [[package]] name = "libfuzzer-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", - "once_cell", ] [[package]] name = "libgit2-sys" -version = "0.18.0+1.9.0" +version = "0.18.2+1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" dependencies = [ "cc", "libc", @@ -9131,25 +9378,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.53.3", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libnghttp2-sys" -version = "0.1.9+1.58.0" +version = "0.1.11+1.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b57e858af2798e167e709b9d969325b6d8e9d50232fcbc494d7d54f976854a64" +checksum = "1b6c24e48a7167cffa7119da39d577fa482e66c688a4aac016bee862e1a713c4" dependencies = [ "cc", "libc", @@ -9165,7 +9412,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom 0.2.16", "libp2p-allow-block-list", "libp2p-connection-limits", "libp2p-core", @@ -9184,10 +9431,10 @@ dependencies = [ "libp2p-upnp", "libp2p-websocket", "libp2p-yamux", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "pin-project", "rw-stream-sink", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -9225,17 +9472,17 @@ dependencies = [ "futures", "futures-timer", "libp2p-identity", - "multiaddr 0.18.1", - "multihash 0.19.1", + "multiaddr 0.18.2", + "multihash 0.19.3", "multistream-select", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "quick-protobuf", "rand 0.8.5", "rw-stream-sink", "smallvec", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "unsigned-varint 0.8.0", "void", @@ -9250,10 +9497,10 @@ checksum = "97f37f30d5c7275db282ecd86e54f29dd2176bd3ac656f06abf43bedb21eb8bd" dependencies = [ "async-trait", "futures", - "hickory-resolver 0.24.2", + "hickory-resolver 0.24.4", "libp2p-core", "libp2p-identity", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "smallvec", "tracing", ] @@ -9272,29 +9519,29 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "lru 0.12.3", + "lru 0.12.5", "quick-protobuf", "quick-protobuf-codec", "smallvec", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "void", ] [[package]] name = "libp2p-identity" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +checksum = "3104e13b51e4711ff5738caa1fb54467c8604c2e94d607e27745bcf709068774" dependencies = [ "bs58", "ed25519-dalek", "hkdf", - "multihash 0.19.1", + "multihash 0.19.3", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", - "thiserror 1.0.65", + "sha2 0.10.9", + "thiserror 2.0.16", "tracing", "zeroize", ] @@ -9319,9 +9566,9 @@ dependencies = [ "quick-protobuf", "quick-protobuf-codec", "rand 0.8.5", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "uint 0.9.5", "void", @@ -9336,14 +9583,14 @@ checksum = "14b8546b6644032565eb29046b42744aee1e9f261ed99671b2c93fb140dba417" dependencies = [ "data-encoding", "futures", - "hickory-proto 0.24.1", + "hickory-proto 0.24.4", "if-watch", "libp2p-core", "libp2p-identity", "libp2p-swarm", "rand 0.8.5", "smallvec", - "socket2 0.5.9", + "socket2 0.5.10", "tokio", "tracing", "void", @@ -9379,15 +9626,15 @@ dependencies = [ "futures", "libp2p-core", "libp2p-identity", - "multiaddr 0.18.1", - "multihash 0.19.1", + "multiaddr 0.18.2", + "multihash 0.19.3", "once_cell", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", + "sha2 0.10.9", "snow", "static_assertions", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "x25519-dalek", "zeroize", @@ -9424,13 +9671,13 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-tls", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "quinn", "rand 0.8.5", - "ring 0.17.8", - "rustls 0.23.18", - "socket2 0.5.9", - "thiserror 1.0.65", + "ring 0.17.14", + "rustls 0.23.31", + "socket2 0.5.10", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -9468,7 +9715,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm-derive", - "lru 0.12.3", + "lru 0.12.5", "multistream-select", "once_cell", "rand 0.8.5", @@ -9486,9 +9733,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9503,7 +9750,7 @@ dependencies = [ "libc", "libp2p-core", "libp2p-identity", - "socket2 0.5.9", + "socket2 0.5.10", "tokio", "tracing", ] @@ -9519,10 +9766,10 @@ dependencies = [ "libp2p-core", "libp2p-identity", "rcgen", - "ring 0.17.8", - "rustls 0.23.18", - "rustls-webpki 0.101.4", - "thiserror 1.0.65", + "ring 0.17.14", + "rustls 0.23.31", + "rustls-webpki 0.101.7", + "thiserror 1.0.69", "x509-parser 0.16.0", "yasna", ] @@ -9554,14 +9801,14 @@ dependencies = [ "futures-rustls", "libp2p-core", "libp2p-identity", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "rw-stream-sink", - "soketto 0.8.0", - "thiserror 1.0.65", + "soketto 0.8.1", + "thiserror 1.0.69", "tracing", "url", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", ] [[package]] @@ -9573,12 +9820,23 @@ dependencies = [ "either", "futures", "libp2p-core", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "yamux 0.12.1", "yamux 0.13.6", ] +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.3", + "libc", + "redox_syscall 0.5.17", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -9596,12 +9854,12 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" dependencies = [ "arrayref", - "base64 0.13.1", + "base64 0.22.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -9621,7 +9879,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -9655,9 +9913,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -9667,9 +9925,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" dependencies = [ "cc", ] @@ -9682,18 +9940,18 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linked_hash_set" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +checksum = "bae85b5be22d9843c80e5fc80e9b64c8a3b1f98f867c709956eca3efff4e92e2" dependencies = [ "linked-hash-map", ] [[package]] name = "linregress" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" +checksum = "a9eda9dcf4f2a99787827661f312ac3219292549c2ee992bf9a6248ffb066bf7" dependencies = [ "nalgebra", ] @@ -9706,9 +9964,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" @@ -9748,9 +10006,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litep2p" @@ -9772,18 +10030,18 @@ dependencies = [ "multiaddr 0.17.1", "multihash 0.17.0", "network-interface", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "prost 0.13.5", "prost-build", "rand 0.8.5", "serde", - "sha2 0.10.8", + "sha2 0.10.9", "simple-dns", "smallvec", "snow", - "socket2 0.5.9", - "thiserror 2.0.12", + "socket2 0.5.10", + "thiserror 2.0.16", "tokio", "tokio-stream", "tokio-tungstenite 0.27.0", @@ -9801,9 +10059,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -9811,9 +10069,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" dependencies = [ "serde", "value-bag", @@ -9829,22 +10087,22 @@ dependencies = [ "generator", "scoped-tls", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] name = "lru" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.5", ] [[package]] @@ -9856,21 +10114,26 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz4" -version = "1.24.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -9878,9 +10141,9 @@ dependencies = [ [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ "libc", ] @@ -9891,9 +10154,9 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9905,7 +10168,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9917,9 +10180,9 @@ dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9928,9 +10191,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9941,7 +10204,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -9950,12 +10213,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - [[package]] name = "matchers" version = "0.1.0" @@ -9967,9 +10224,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.7" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ "autocfg", "rawpointer", @@ -9987,17 +10244,17 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.23", + "rustix 0.38.44", ] [[package]] @@ -10011,31 +10268,22 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-db" version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e300c54e3239a86f9c61cc63ab0f03862eb40b1c6e065dc6fd6ceaeff6da93d" dependencies = [ - "foldhash", + "foldhash 0.1.5", "hash-db", - "hashbrown 0.15.3", + "hashbrown 0.15.5", ] [[package]] @@ -10044,7 +10292,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3e3e3f549d27d2dc054372f320ddf68045a833fab490563ff70d4cf1b9d91ea" dependencies = [ - "array-bytes 9.1.2", + "array-bytes 9.3.0", "blake3", "frame-metadata 23.0.0", "parity-scale-codec", @@ -10076,7 +10324,7 @@ dependencies = [ "hex", "log", "num-traits", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "relay-utils", "sp-arithmetic", "sp-core 28.0.0", @@ -10120,23 +10368,22 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ - "hermit-abi", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -10155,12 +10402,12 @@ dependencies = [ "hashlink 0.8.4", "lioness", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", - "subtle 2.5.0", - "thiserror 1.0.65", + "subtle 2.6.1", + "thiserror 1.0.69", "zeroize", ] @@ -10171,7 +10418,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-offchain", @@ -10223,9 +10470,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" dependencies = [ "cfg-if", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -10238,12 +10485,12 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "loom", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "portable-atomic", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "smallvec", "tagptr", - "thiserror 1.0.65", + "thiserror 1.0.69", "uuid", ] @@ -10274,20 +10521,20 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", "data-encoding", "libp2p-identity", "multibase", - "multihash 0.19.1", + "multihash 0.19.3", "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -10314,30 +10561,30 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "unsigned-varint 0.7.2", ] [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 1.1.3", "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", "synstructure 0.12.6", @@ -10345,9 +10592,9 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "multistream-select" @@ -10365,13 +10612,12 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.3" +version = "0.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" dependencies = [ "approx", "matrixmultiply", - "nalgebra-macros", "num-complex", "num-rational", "num-traits", @@ -10379,17 +10625,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "nalgebra-macros" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" -dependencies = [ - "proc-macro2 1.0.95", - "quote 1.0.40", - "syn 1.0.109", -] - [[package]] name = "names" version = "0.14.0" @@ -10407,9 +10642,9 @@ checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -10417,28 +10652,27 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] [[package]] name = "netlink-packet-core" -version = "0.4.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", - "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" -version = "0.12.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -10457,29 +10691,28 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "netlink-proto" -version = "0.10.0" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", - "thiserror 1.0.65", - "tokio", + "thiserror 2.0.16", ] [[package]] name = "netlink-sys" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ "bytes", "futures", @@ -10490,21 +10723,21 @@ dependencies = [ [[package]] name = "network-interface" -version = "2.0.1" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3329f515506e4a2de3aa6e07027a6758e22e0f0e8eaf64fa47261cec2282602" +checksum = "07709a6d4eba90ab10ec170a0530b3aafc81cb8a2d380e4423ae41fc55fe5745" dependencies = [ "cc", "libc", - "thiserror 1.0.65", + "thiserror 2.0.16", "winapi", ] [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -10517,7 +10750,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "cfg-if", "libc", ] @@ -10528,7 +10761,19 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.3", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -10550,10 +10795,10 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-trait", "clap", - "derive_more 0.99.17", + "derive_more 0.99.20", "fs_extra", "futures", "hash-db", @@ -10747,9 +10992,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -10761,11 +11006,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -10789,9 +11033,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] @@ -10808,9 +11052,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -10834,9 +11078,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -10845,11 +11089,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -10867,14 +11110,36 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.2", "libc", ] +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.106", +] + [[package]] name = "num_threads" version = "0.1.7" @@ -10890,15 +11155,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.36.7" @@ -10906,18 +11162,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "indexmap", "memchr", ] [[package]] name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", ] [[package]] @@ -10926,7 +11182,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ - "asn1-rs 0.7.0", + "asn1-rs 0.7.1", ] [[package]] @@ -10939,11 +11195,17 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "opaque-debug" @@ -10953,17 +11215,17 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "cfg-if", "foreign-types", "libc", @@ -10978,22 +11240,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -11020,7 +11282,7 @@ dependencies = [ "orchestra-proc-macro", "pin-project", "prioritized-metered-channel", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", ] @@ -11033,9 +11295,9 @@ dependencies = [ "expander", "indexmap", "itertools 0.11.0", - "petgraph", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "petgraph 0.6.5", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -11051,9 +11313,9 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" dependencies = [ "libc", "windows-sys 0.59.0", @@ -11067,9 +11329,21 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" -version = "3.5.0" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" + +[[package]] +name = "p256" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] [[package]] name = "pallet-ah-ops" @@ -11121,7 +11395,7 @@ dependencies = [ name = "pallet-alliance" version = "27.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-benchmarking", "frame-support", "frame-system", @@ -11476,7 +11750,7 @@ dependencies = [ name = "pallet-beefy-mmr" version = "28.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "binary-merkle-tree", "frame-benchmarking", "frame-support", @@ -11729,7 +12003,7 @@ dependencies = [ name = "pallet-contracts" version = "27.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "environmental", "frame-benchmarking", @@ -11775,7 +12049,7 @@ dependencies = [ "parity-wasm", "sp-runtime", "tempfile", - "toml", + "toml 0.8.23", "twox-hash 1.6.3", ] @@ -11814,9 +12088,9 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -11988,7 +12262,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "scale-info", "sp-core 28.0.0", "sp-io", @@ -12009,7 +12283,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -12034,7 +12308,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -12894,9 +13168,9 @@ name = "pallet-revive" version = "0.1.0" dependencies = [ "alloy-core", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", - "derive_more 0.99.17", + "derive_more 0.99.20", "environmental", "ethereum-standards", "ethereum-types", @@ -12925,6 +13199,7 @@ dependencies = [ "pretty_assertions", "rand 0.8.5", "rand_pcg", + "revm", "ripemd", "rlp 0.6.1", "scale-info", @@ -12951,7 +13226,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "env_logger 0.11.3", + "env_logger 0.11.8", "futures", "git2", "hex", @@ -12979,7 +13254,7 @@ dependencies = [ "substrate-prometheus-endpoint", "subxt 0.41.0", "subxt-signer 0.41.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -12987,22 +13262,25 @@ dependencies = [ name = "pallet-revive-fixtures" version = "0.1.0" dependencies = [ + "alloy-core", "anyhow", "cargo_metadata", + "hex", "pallet-revive-uapi", "polkavm-linker 0.27.0", + "serde_json", "sp-core 28.0.0", "sp-io", - "toml", + "toml 0.8.23", ] [[package]] name = "pallet-revive-proc-macro" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -13076,7 +13354,7 @@ dependencies = [ name = "pallet-sassafras" version = "0.3.5-dev" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-benchmarking", "frame-support", "frame-system", @@ -13229,7 +13507,7 @@ name = "pallet-staking-async" version = "0.1.0" dependencies = [ "anyhow", - "env_logger 0.11.3", + "env_logger 0.11.8", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -13556,11 +13834,11 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", "sp-runtime", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -13731,7 +14009,7 @@ dependencies = [ name = "pallet-transaction-storage" version = "27.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-benchmarking", "frame-support", "frame-system", @@ -14082,9 +14360,9 @@ checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" [[package]] name = "parity-db" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" +checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" dependencies = [ "blake2 0.10.6", "crc32fast", @@ -14094,10 +14372,11 @@ dependencies = [ "log", "lz4", "memmap2 0.5.10", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "siphasher 0.3.11", "snap", + "winapi", ] [[package]] @@ -14123,10 +14402,10 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -14154,12 +14433,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.11", ] [[package]] @@ -14178,15 +14457,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.5.17", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -14203,7 +14482,7 @@ checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -14231,9 +14510,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ "base64 0.22.1", "serde", @@ -14532,25 +14811,26 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.7.2" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ - "thiserror 1.0.65", + "memchr", + "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -14558,38 +14838,89 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap", +] + +[[package]] +name = "petgraph" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ - "fixedbitset", + "fixedbitset 0.5.7", "indexmap", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.106", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -14605,16 +14936,16 @@ version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -14622,6 +14953,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.3.0", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -14651,9 +14993,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -14664,15 +15006,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -14718,7 +15060,7 @@ dependencies = [ "rand_chacha 0.3.1", "rand_core 0.6.4", "sc-keystore", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "sp-application-crypto", "sp-authority-discovery", "sp-core 28.0.0", @@ -14777,7 +15119,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -14807,7 +15149,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing-gum", ] @@ -14844,7 +15186,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "substrate-build-script-utils", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -14874,7 +15216,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing-gum", @@ -14915,7 +15257,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -14931,7 +15273,7 @@ dependencies = [ "reed-solomon-novelpoly", "sp-core 28.0.0", "sp-trie", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -14942,7 +15284,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -14975,7 +15317,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -14988,7 +15330,7 @@ dependencies = [ "sp-consensus", "sp-core 28.0.0", "sp-keyring", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15010,7 +15352,7 @@ dependencies = [ "schnellru", "sp-core 28.0.0", "sp-keyring", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15021,14 +15363,14 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "derive_more 0.99.17", + "derive_more 0.99.20", "futures", "futures-timer", "itertools 0.11.0", "kvdb-memorydb", "merlin", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -15042,7 +15384,7 @@ dependencies = [ "rand_core 0.6.4", "sc-keystore", "schnellru", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "sp-application-crypto", "sp-consensus", "sp-consensus-babe", @@ -15052,7 +15394,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15078,7 +15420,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "sc-keystore", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "sp-consensus", "sp-consensus-babe", "sp-core 28.0.0", @@ -15097,7 +15439,7 @@ dependencies = [ "futures-timer", "kvdb-memorydb", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -15109,7 +15451,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15137,7 +15479,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15152,7 +15494,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "sp-keystore", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", "wasm-timer", ] @@ -15214,14 +15556,14 @@ dependencies = [ "futures-timer", "kvdb-memorydb", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-primitives", "sp-core 28.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15249,7 +15591,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15265,7 +15607,7 @@ dependencies = [ "polkadot-primitives", "sp-blockchain", "sp-inherents", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15285,7 +15627,7 @@ dependencies = [ "rstest", "sp-core 28.0.0", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15305,7 +15647,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "sp-application-crypto", "sp-keystore", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15314,7 +15656,7 @@ name = "polkadot-node-core-pvf" version = "7.0.0" dependencies = [ "always-assert", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "criterion", "futures", @@ -15346,7 +15688,7 @@ dependencies = [ "tempfile", "test-parachain-adder", "test-parachain-halt", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing-gum", ] @@ -15395,7 +15737,7 @@ dependencies = [ "sp-io", "sp-tracing 16.0.0", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15464,7 +15806,7 @@ dependencies = [ "futures", "futures-timer", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "parity-scale-codec", "polkadot-primitives", @@ -15486,7 +15828,7 @@ dependencies = [ "async-channel 1.9.0", "async-trait", "bitvec", - "derive_more 0.99.17", + "derive_more 0.99.20", "fatality", "futures", "hex", @@ -15500,7 +15842,7 @@ dependencies = [ "sc-network-types", "sp-runtime", "strum 0.26.3", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15516,14 +15858,14 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "sc-keystore", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "serde", "sp-application-crypto", "sp-consensus-babe", "sp-consensus-slots", "sp-keystore", "sp-maybe-compressed-blob", - "thiserror 1.0.65", + "thiserror 1.0.69", "zstd 0.12.4", ] @@ -15541,7 +15883,7 @@ version = "1.0.0" dependencies = [ "async-trait", "futures", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -15561,7 +15903,7 @@ name = "polkadot-node-subsystem-types" version = "7.0.0" dependencies = [ "async-trait", - "derive_more 0.99.17", + "derive_more 0.99.20", "fatality", "futures", "orchestra", @@ -15580,7 +15922,7 @@ dependencies = [ "sp-consensus-babe", "sp-runtime", "substrate-prometheus-endpoint", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -15595,7 +15937,7 @@ dependencies = [ "kvdb-shared-tests", "parity-db", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-erasure-coding", "polkadot-node-metrics", "polkadot-node-network-protocol", @@ -15613,7 +15955,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keystore", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -15783,7 +16125,7 @@ name = "polkadot-parachain-primitives" version = "6.0.0" dependencies = [ "bounded-collections 0.3.2", - "derive_more 0.99.17", + "derive_more 0.99.20", "parity-scale-codec", "polkadot-core-primitives", "scale-info", @@ -15818,7 +16160,7 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-std 14.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -16558,7 +16900,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -16646,7 +16988,7 @@ dependencies = [ "staging-xcm", "substrate-prometheus-endpoint", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", "westend-runtime", "westend-runtime-constants", @@ -16682,7 +17024,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing-gum", ] @@ -16927,7 +17269,7 @@ version = "0.1.0" dependencies = [ "anyhow", "cumulus-zombienet-sdk-helpers", - "env_logger 0.11.3", + "env_logger 0.11.8", "log", "parity-scale-codec", "polkadot-primitives", @@ -17049,9 +17391,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f2116a92e6e96220a398930f4c8a6cda1264206f3e2034fc9982bfd93f261f7" dependencies = [ "polkavm-common 0.18.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17061,9 +17403,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6069dc7995cde6e612b868a02ce48b54397c6d2582bd1b97b63aabbe962cd779" dependencies = [ "polkavm-common 0.26.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17073,9 +17415,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8abdd1210d96b1dda9ac21199ec469448fd628cea102e2ff0e0df1667c4c3b5f" dependencies = [ "polkavm-common 0.27.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17085,7 +17427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c16669ddc7433e34c1007d31080b80901e3e8e523cb9d4b441c3910cf9294b" dependencies = [ "polkavm-derive-impl 0.18.1", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17095,7 +17437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581d34cafec741dc5ffafbb341933c205b6457f3d76257a9d99fb56687219c91" dependencies = [ "polkavm-derive-impl 0.26.0", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17105,7 +17447,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a45173d70138aa1879892c50777ed0d8b0c8556f7678372f09fa1d89bbbddb4" dependencies = [ "polkavm-derive-impl 0.27.0", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17115,10 +17457,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "beb896023e5bd89bba40311797d8d42490fa4a1fd5256c74820753c5722d1e67" dependencies = [ "dirs", - "gimli 0.31.1", + "gimli", "hashbrown 0.14.5", "log", - "object 0.36.7", + "object", "polkavm-common 0.26.0", "regalloc2 0.9.3", "rustc-demangle", @@ -17131,10 +17473,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99fe3704d21e96c5d1e6a1b1a43ac57f9dce110d3331fbf8299e9f57d5884066" dependencies = [ "dirs", - "gimli 0.31.1", + "gimli", "hashbrown 0.14.5", "log", - "object 0.36.7", + "object", "polkavm-common 0.27.0", "regalloc2 0.9.3", "rustc-demangle", @@ -17170,16 +17512,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix 0.38.42", - "tracing", - "windows-sys 0.52.0", + "rustix 1.0.8", + "windows-sys 0.60.2", ] [[package]] @@ -17189,27 +17531,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "portpicker" @@ -17232,6 +17583,15 @@ dependencies = [ "serde", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -17251,42 +17611,44 @@ dependencies = [ "log", "nix 0.27.1", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "smallvec", "symbolic-demangle", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" -version = "3.0.3" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "difflib", - "itertools 0.10.5", "predicates-core", ] [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -17294,9 +17656,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -17304,12 +17666,21 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.12" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2 1.0.101", + "syn 2.0.106", +] + +[[package]] +name = "primeorder" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "proc-macro2 1.0.95", - "syn 2.0.98", + "elliptic-curve", ] [[package]] @@ -17346,31 +17717,31 @@ checksum = "a172e6cc603231f2cf004232eabcecccc0da53ba576ab286ef7baa0cfc7927ad" dependencies = [ "coarsetime", "crossbeam-queue", - "derive_more 0.99.17", + "derive_more 0.99.20", "futures", "futures-timer", "nanorand", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", ] [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "thiserror 1.0.69", + "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.21.0", + "toml_edit 0.22.27", ] [[package]] @@ -17380,7 +17751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", "version_check", @@ -17392,7 +17763,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "version_check", ] @@ -17403,7 +17774,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", ] @@ -17414,26 +17785,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ "proc-macro-error-attr2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro-warning" -version = "1.0.0" +version = "1.84.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" +checksum = "75eea531cfcd120e0851a3f8aed42c4841f78c889eefafd96339c72677ae42c3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17447,9 +17812,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -17460,13 +17825,13 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "chrono", "flate2", "hex", "lazy_static", "procfs-core", - "rustix 0.38.42", + "rustix 0.38.44", ] [[package]] @@ -17475,23 +17840,23 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "chrono", "hex", ] [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ "cfg-if", "fnv", "lazy_static", "memchr", - "parking_lot 0.12.3", - "thiserror 1.0.65", + "parking_lot 0.12.4", + "thiserror 1.0.69", ] [[package]] @@ -17502,7 +17867,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "prometheus-client-derive-encode", ] @@ -17512,38 +17877,38 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "prometheus-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2aa5feb83bf4b2c8919eaf563f51dbab41183de73ba2353c0e03cd7b6bd892" +checksum = "811031bea65e5a401fb2e1f37d802cca6601e204ac463809a3189352d13b78a5" dependencies = [ "chrono", - "itertools 0.10.5", + "itertools 0.12.1", "once_cell", "regex", ] [[package]] name = "proptest" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.9.3", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.2", + "rand_chacha 0.9.0", "rand_xorshift", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", "rusty-fork", "tempfile", "unarray", @@ -17581,22 +17946,21 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ - "bytes", "heck 0.5.0", - "itertools 0.13.0", + "itertools 0.14.0", "log", "multimap", "once_cell", - "petgraph", + "petgraph 0.7.1", "prettyplease", "prost 0.13.5", "prost-types", "regex", - "syn 2.0.98", + "syn 2.0.106", "tempfile", ] @@ -17608,7 +17972,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -17621,9 +17985,9 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17634,16 +17998,16 @@ checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", "itertools 0.14.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "prost-types" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ "prost 0.13.5", ] @@ -17666,9 +18030,9 @@ version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "938543690519c20c3a480d20a8efcc8e69abeb44093ab1df4e7c1f81f26c677a" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -17684,35 +18048,33 @@ dependencies = [ "prost 0.11.9", "reqwest", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "url", "winapi", ] [[package]] name = "pyroscope_pprofrs" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614a25777053da6bdca9d84a67892490b5a57590248dbdee3d7bf0716252af70" +checksum = "50da7a8950c542357de489aa9ee628f46322b1beaac1f4fa3313bcdebe85b4ea" dependencies = [ "log", "pprof2", "pyroscope", - "thiserror 1.0.65", ] [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -17741,7 +18103,7 @@ dependencies = [ "asynchronous-codec 0.7.0", "bytes", "quick-protobuf", - "thiserror 1.0.65", + "thiserror 1.0.69", "unsigned-varint 0.8.0", ] @@ -17753,7 +18115,7 @@ checksum = "5253a3a0d56548d5b0be25414171dc780cc6870727746d05bd2bde352eee96c5" dependencies = [ "ahash", "hashbrown 0.13.2", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -17769,51 +18131,58 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", + "cfg_aliases 0.2.1", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.18", - "socket2 0.5.9", - "thiserror 1.0.65", + "rustls 0.23.31", + "socket2 0.5.10", + "thiserror 2.0.16", "tokio", "tracing", + "web-time", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "rand 0.8.5", - "ring 0.17.8", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring 0.17.14", "rustc-hash 2.1.1", - "rustls 0.23.18", + "rustls 0.23.31", + "rustls-pki-types", "slab", - "thiserror 1.0.65", + "thiserror 2.0.16", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ + "cfg_aliases 0.2.1", "libc", "once_cell", - "socket2 0.5.9", + "socket2 0.5.10", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -17831,9 +18200,15 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "radium" version = "0.7.0" @@ -17853,14 +18228,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.1", + "rand_core 0.9.3", "serde", - "zerocopy 0.8.20", ] [[package]] @@ -17880,7 +18254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.1", + "rand_core 0.9.3", ] [[package]] @@ -17889,18 +18263,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", "serde", - "zerocopy 0.8.20", ] [[package]] @@ -17924,20 +18297,20 @@ dependencies = [ [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.3", ] [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.3", ] [[package]] @@ -17948,9 +18321,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -17958,9 +18331,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -18009,31 +18382,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.8" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", - "thiserror 1.0.65", + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", ] [[package]] @@ -18042,30 +18406,30 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87413ebb313323d431e85d0afc5a68222aaed972843537cbfe5f061cf1b4bcab" dependencies = [ - "derive_more 0.99.17", + "derive_more 0.99.20", "fs-err", "static_init", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -18089,7 +18453,7 @@ checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "log", "rustc-hash 2.1.1", "smallvec", @@ -18097,14 +18461,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", + "regex-automata 0.4.10", + "regex-syntax 0.8.6", ] [[package]] @@ -18118,19 +18482,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" - -[[package]] -name = "regex-automata" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] @@ -18141,15 +18499,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "relative-path" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "relay-substrate-client" @@ -18187,7 +18545,7 @@ dependencies = [ "sp-trie", "sp-version", "staging-xcm", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -18205,13 +18563,13 @@ dependencies = [ "jsonpath_lib", "log", "num-traits", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "serde_json", "sp-runtime", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "sysinfo", - "thiserror 1.0.65", + "thiserror 1.0.69", "time", "tokio", ] @@ -18233,9 +18591,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64 0.22.1", "bytes", @@ -18243,52 +18601,45 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", - "hyper-rustls 0.27.3", + "hyper 1.7.0", + "hyper-rustls 0.27.7", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.18", - "rustls-pemfile 2.0.0", + "rustls 0.23.31", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration 0.6.1", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.2", + "tower 0.5.2", + "tower-http 0.6.6", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.3", - "windows-registry", + "webpki-roots 1.0.2", ] [[package]] name = "resolv-conf" -version = "0.7.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", -] +checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" [[package]] name = "revive-dev-node" @@ -18307,7 +18658,7 @@ dependencies = [ name = "revive-dev-runtime" version = "0.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "parity-scale-codec", "polkadot-sdk 0.1.0", "scale-info", @@ -18315,13 +18666,202 @@ dependencies = [ ] [[package]] -name = "rfc6979" -version = "0.4.0" +name = "revm" +version = "27.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "5e6bf82101a1ad8a2b637363a37aef27f88b4efc8a6e24c72bf5f64923dc5532" dependencies = [ - "hmac 0.12.1", - "subtle 2.5.0", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c52031b73cae95d84cd1b07725808b5fd1500da3e5e24574a3b2dc13d9f16d" +dependencies = [ + "bitvec", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" +dependencies = [ + "cfg-if", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc90302642d21c8f93e0876e201f3c5f7913c4fcb66fb465b0fd7b707dfe1c79" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" +dependencies = [ + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c523c77e74eeedbac5d6f7c092e3851dbe9c7fec6f418b85992bd79229db361" +dependencies = [ + "auto_impl", + "either", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-handler" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1529c8050e663be64010e80ec92bf480315d21b1f2dbf65540028653a621b27d" +dependencies = [ + "auto_impl", + "derive-where", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78db140e332489094ef314eaeb0bd1849d6d01172c113ab0eb6ea8ab9372926" +dependencies = [ + "auto_impl", + "either", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", + "serde", + "serde_json", +] + +[[package]] +name = "revm-interpreter" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff9d7d9d71e8a33740b277b602165b6e3d25fff091ba3d7b5a8d373bf55f28a7" +dependencies = [ + "revm-bytecode", + "revm-context-interface", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-precompile" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cee3f336b83621294b4cfe84d817e3eef6f3d0fce00951973364cc7f860424d" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-bn254", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayref", + "aurora-engine-modexp", + "c-kzg", + "cfg-if", + "k256", + "libsecp256k1", + "once_cell", + "p256", + "revm-primitives", + "ripemd", + "rug", + "secp256k1 0.31.1", + "sha2 0.10.9", +] + +[[package]] +name = "revm-primitives" +version = "20.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa29d9da06fe03b249b6419b33968ecdf92ad6428e2f012dc57bcd619b5d94e" +dependencies = [ + "alloy-primitives", + "num_enum", + "once_cell", + "serde", +] + +[[package]] +name = "revm-state" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" +dependencies = [ + "bitflags 2.9.3", + "revm-bytecode", + "revm-primitives", + "serde", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle 2.6.1", ] [[package]] @@ -18341,15 +18881,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.10", + "getrandom 0.2.16", "libc", - "spin 0.9.8", "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -18618,20 +19157,20 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.2.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "rsa" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af6c4b23d99685a1408194da11270ef8e9809aff951cc70ec9b17350b087e474" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ "const-oid", "digest 0.10.7", @@ -18643,7 +19182,7 @@ dependencies = [ "rand_core 0.6.4", "signature", "spki", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -18656,7 +19195,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -18667,45 +19206,60 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "relative-path", - "rustc_version 0.4.0", - "syn 2.0.98", + "rustc_version 0.4.1", + "syn 2.0.106", "unicode-ident", ] [[package]] name = "rtnetlink" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" dependencies = [ "futures", "log", + "netlink-packet-core", "netlink-packet-route", + "netlink-packet-utils", "netlink-proto", - "nix 0.24.3", - "thiserror 1.0.65", + "netlink-sys", + "nix 0.26.4", + "thiserror 1.0.69", "tokio", ] [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", +] + +[[package]] +name = "rug" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad2e973fe3c3214251a840a621812a4f40468da814b1a3d6947d433c2af11f" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", ] [[package]] name = "ruint" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" +checksum = "9ecb38f82477f20c5c3d62ef52d7c4e536e38ea9b73fb570a20c5cae0e14bcf6" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -18720,7 +19274,7 @@ dependencies = [ "primitive-types 0.12.2", "proptest", "rand 0.8.5", - "rand 0.9.0", + "rand 0.9.2", "rlp 0.5.2", "ruint-macro", "serde", @@ -18736,9 +19290,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -18778,11 +19332,11 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.18", + "semver 1.0.26", ] [[package]] @@ -18796,9 +19350,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" dependencies = [ "bitflags 1.3.2", "errno", @@ -18810,14 +19364,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] @@ -18827,37 +19381,37 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.16.20", - "rustls-webpki 0.101.4", + "ring 0.17.14", + "rustls-webpki 0.101.7", "sct", ] [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "log", "once_cell", - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.102.8", - "subtle 2.5.0", + "rustls-webpki 0.103.4", + "subtle 2.6.1", "zeroize", ] @@ -18868,115 +19422,95 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.3", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-native-certs" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.0.0", - "rustls-pki-types", + "rustls-pemfile", "schannel", - "security-framework", + "security-framework 2.11.1", ] [[package]] name = "rustls-native-certs" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile 2.0.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.3.0", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] [[package]] -name = "rustls-pemfile" -version = "2.0.0" +name = "rustls-pki-types" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ - "base64 0.21.7", - "rustls-pki-types", + "web-time", + "zeroize", ] -[[package]] -name = "rustls-pki-types" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" - [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.18", - "rustls-native-certs 0.7.0", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", "rustls-platform-verifier-android", - "rustls-webpki 0.102.8", - "security-framework", + "rustls-webpki 0.103.4", + "security-framework 3.3.0", "security-framework-sys", - "webpki-roots 0.26.3", - "winapi", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", ] [[package]] name = "rustls-platform-verifier-android" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.14", + "untrusted 0.9.0", ] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" @@ -19008,7 +19542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" dependencies = [ "byteorder", - "derive_more 0.99.17", + "derive_more 0.99.20", ] [[package]] @@ -19030,9 +19564,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safe-mix" @@ -19045,9 +19579,9 @@ dependencies = [ [[package]] name = "safe_arch" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" dependencies = [ "bytemuck", ] @@ -19077,7 +19611,7 @@ dependencies = [ "log", "sp-core 28.0.0", "sp-wasm-interface 20.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -19112,7 +19646,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19123,7 +19657,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -19161,10 +19695,10 @@ dependencies = [ name = "sc-chain-spec" version = "28.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "clap", "docify", - "memmap2 0.9.3", + "memmap2 0.9.8", "parity-scale-codec", "pretty_assertions", "regex", @@ -19193,17 +19727,17 @@ dependencies = [ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "sc-cli" version = "0.36.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "chrono", "clap", "fdlimit", @@ -19239,7 +19773,7 @@ dependencies = [ "sp-tracing 16.0.0", "sp-version", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19251,7 +19785,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -19273,7 +19807,7 @@ dependencies = [ name = "sc-client-db" version = "0.35.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "criterion", "hash-db", "kitchensink-runtime", @@ -19284,7 +19818,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "sc-client-api", "sc-state-db", @@ -19311,7 +19845,7 @@ dependencies = [ "futures", "log", "mockall", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-client-api", "sc-network-types", "sc-utils", @@ -19323,7 +19857,7 @@ dependencies = [ "sp-state-machine", "sp-test-primitives", "substrate-prometheus-endpoint", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -19334,7 +19868,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -19360,7 +19894,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19376,7 +19910,7 @@ dependencies = [ "num-rational", "num-traits", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -19402,7 +19936,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19428,7 +19962,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19436,13 +19970,13 @@ dependencies = [ name = "sc-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "async-trait", "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -19466,7 +20000,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "wasm-timer", ] @@ -19479,7 +20013,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-consensus-beefy", "sc-rpc", "serde", @@ -19488,7 +20022,7 @@ dependencies = [ "sp-core 28.0.0", "sp-runtime", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19509,7 +20043,7 @@ name = "sc-consensus-grandpa" version = "0.19.0" dependencies = [ "ahash", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "async-trait", "dyn-clone", @@ -19519,7 +20053,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "sc-block-builder", "sc-chain-spec", @@ -19549,7 +20083,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19573,7 +20107,7 @@ dependencies = [ "sp-keyring", "sp-runtime", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19611,7 +20145,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -19624,7 +20158,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-client-api", "sc-consensus", "sp-api", @@ -19636,7 +20170,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "substrate-prometheus-endpoint", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -19666,12 +20200,12 @@ dependencies = [ name = "sc-executor" version = "0.32.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "criterion", "num_cpus", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "paste", "sc-executor-common", "sc-executor-polkavm", @@ -19696,7 +20230,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "wat", ] @@ -19708,7 +20242,7 @@ dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", "sp-wasm-interface 20.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "wasm-instrument", ] @@ -19730,7 +20264,7 @@ dependencies = [ "cargo_metadata", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "paste", "rustix 1.0.8", "sc-allocator", @@ -19763,21 +20297,21 @@ dependencies = [ name = "sc-keystore" version = "25.0.0" dependencies = [ - "array-bytes 6.2.2", - "parking_lot 0.12.3", + "array-bytes 6.2.3", + "parking_lot 0.12.4", "serde_json", "sp-application-crypto", "sp-core 28.0.0", "sp-keystore", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "sc-mixnet" version = "0.4.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "arrayvec 0.7.6", "blake2 0.10.6", "bytes", @@ -19786,7 +20320,7 @@ dependencies = [ "log", "mixnet", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-client-api", "sc-network", "sc-network-types", @@ -19797,14 +20331,14 @@ dependencies = [ "sp-keystore", "sp-mixnet", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "sc-network" version = "0.34.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "async-channel 1.9.0", "async-trait", @@ -19824,7 +20358,7 @@ dependencies = [ "mockall", "multistream-select", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "partial_sort", "pin-project", "prost 0.12.6", @@ -19850,7 +20384,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -19896,7 +20430,7 @@ dependencies = [ name = "sc-network-light" version = "0.33.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "futures", "log", @@ -19909,14 +20443,14 @@ dependencies = [ "sp-blockchain", "sp-core 28.0.0", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "sc-network-statement" version = "0.16.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "futures", "log", @@ -19935,7 +20469,7 @@ dependencies = [ name = "sc-network-sync" version = "0.33.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "async-trait", "fork-tree", @@ -19965,7 +20499,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -19980,7 +20514,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -20006,7 +20540,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.33.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "futures", "log", "parity-scale-codec", @@ -20031,13 +20565,13 @@ dependencies = [ "libp2p-kad", "litep2p", "log", - "multiaddr 0.18.1", - "multihash 0.19.1", + "multiaddr 0.18.2", + "multihash 0.19.3", "quickcheck", "rand 0.8.5", "serde", "serde_with", - "thiserror 1.0.65", + "thiserror 1.0.69", "zeroize", ] @@ -20051,15 +20585,15 @@ dependencies = [ "futures", "futures-timer", "http-body-util", - "hyper 1.6.0", - "hyper-rustls 0.27.3", + "hyper 1.7.0", + "hyper-rustls 0.27.7", "hyper-util", "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", - "rustls 0.23.18", + "rustls 0.23.31", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -20099,7 +20633,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pretty_assertions", "sc-block-builder", "sc-chain-spec", @@ -20144,7 +20678,7 @@ dependencies = [ "sp-rpc", "sp-runtime", "sp-version", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -20155,9 +20689,9 @@ dependencies = [ "forwarded-header-value", "futures", "governor", - "http 1.1.0", + "http 1.3.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "ip_network", "jsonrpsee", "log", @@ -20166,7 +20700,7 @@ dependencies = [ "serde_json", "substrate-prometheus-endpoint", "tokio", - "tower", + "tower 0.4.13", "tower-http 0.5.2", ] @@ -20174,7 +20708,7 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.34.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "async-trait", "futures", @@ -20184,7 +20718,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pretty_assertions", "rand 0.8.5", "sc-block-builder", @@ -20211,7 +20745,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -20243,7 +20777,7 @@ dependencies = [ "sp-version", "sp-wasm-interface 20.0.0", "subxt 0.41.0", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -20258,7 +20792,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "sc-chain-spec", @@ -20305,7 +20839,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing", "tracing-futures", @@ -20315,13 +20849,13 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "fdlimit", "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -20352,7 +20886,7 @@ version = "0.30.0" dependencies = [ "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sp-core 28.0.0", ] @@ -20362,7 +20896,7 @@ version = "10.0.0" dependencies = [ "log", "parity-db", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-client-api", "sc-keystore", "sp-api", @@ -20384,7 +20918,7 @@ dependencies = [ "fs4", "log", "sp-core 28.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -20403,14 +20937,14 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] name = "sc-sysinfo" version = "27.0.0" dependencies = [ - "derive_more 0.99.17", + "derive_more 0.99.20", "futures", "libc", "log", @@ -20434,13 +20968,13 @@ dependencies = [ "futures", "libp2p", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "sc-utils", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "wasm-timer", ] @@ -20455,7 +20989,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "regex", "rustc-hash 1.1.0", "sc-client-api", @@ -20467,20 +21001,20 @@ dependencies = [ "sp-rpc", "sp-runtime", "sp-tracing 16.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "tracing-log", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20493,14 +21027,14 @@ dependencies = [ "chrono", "criterion", "cumulus-zombienet-sdk-helpers", - "env_logger 0.11.3", + "env_logger 0.11.8", "futures", "futures-timer", "indexmap", "itertools 0.11.0", "linked-hash-map", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rstest", "sc-block-builder", "sc-client-api", @@ -20521,11 +21055,11 @@ dependencies = [ "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", "substrate-txtesttool", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "zombienet-configuration", "zombienet-sdk", ] @@ -20544,7 +21078,7 @@ dependencies = [ "sp-blockchain", "sp-core 28.0.0", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -20555,7 +21089,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "prometheus", "sp-arithmetic", "tokio-test", @@ -20612,7 +21146,7 @@ dependencies = [ "scale-decode-derive 0.16.0", "scale-type-resolver", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -20622,9 +21156,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed9401effa946b493f9f84dc03714cca98119b230497df6f3df6b84a2b03648" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20634,9 +21168,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f4b54a1211260718b92832b661025d1f1a4b6930fbadd6908e00edd265fa5f7" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20666,7 +21200,7 @@ dependencies = [ "scale-encode-derive 0.10.0", "scale-type-resolver", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -20676,10 +21210,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "102fbc6236de6c53906c0b262f12c7aa69c2bdc604862c12728f5f4d370bc137" dependencies = [ "darling", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20689,10 +21223,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78a3993a13b4eafa89350604672c8757b7ea84c7c5947d4b3691e3169c96379b" dependencies = [ "darling", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20715,10 +21249,10 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -20737,11 +21271,11 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc4c70c7fea2eef1740f0081d3fe385d8bee1eef11e9272d3bec7dc8e5438e0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", - "syn 2.0.98", - "thiserror 1.0.65", + "syn 2.0.106", + "thiserror 1.0.69", ] [[package]] @@ -20750,11 +21284,11 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05c61b6b706a3eaad63b506ab50a1d2319f817ae01cf753adcc3f055f9f0fcd6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", - "syn 2.0.98", - "thiserror 2.0.12", + "syn 2.0.106", + "thiserror 2.0.16", ] [[package]] @@ -20792,48 +21326,73 @@ dependencies = [ "scale-encode 0.10.0", "scale-type-resolver", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "yap 0.12.0", ] [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive 0.8.22", + "serde", + "serde_json", ] [[package]] name = "schemars" -version = "0.8.13" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ "dyn-clone", - "schemars_derive", + "ref-cast", + "schemars_derive 1.0.4", "serde", "serde_json", ] [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.106", +] + +[[package]] +name = "schemars_derive" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +dependencies = [ + "proc-macro2 1.0.101", + "quote 1.0.40", + "serde_derive_internals", + "syn 2.0.106", ] [[package]] name = "schnellru" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" dependencies = [ "ahash", "cfg-if", @@ -20859,9 +21418,9 @@ dependencies = [ [[package]] name = "schnorrkel" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" +checksum = "6e9fcb6c2e176e86ec703e22560d99d65a5ee9056ae45a08e13e84ebf796296f" dependencies = [ "aead", "arrayref", @@ -20871,8 +21430,8 @@ dependencies = [ "merlin", "rand_core 0.6.4", "serde_bytes", - "sha2 0.10.8", - "subtle 2.5.0", + "sha2 0.10.9", + "subtle 2.6.1", "zeroize", ] @@ -20890,9 +21449,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" [[package]] name = "scrypt" @@ -20903,17 +21462,17 @@ dependencies = [ "password-hash", "pbkdf2", "salsa20", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.14", + "untrusted 0.9.0", ] [[package]] @@ -20927,7 +21486,7 @@ dependencies = [ "generic-array 0.14.7", "pkcs8", "serdect", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -20940,6 +21499,15 @@ dependencies = [ "libc", ] +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys 0.8.2", +] + [[package]] name = "secp256k1" version = "0.28.2" @@ -20960,6 +21528,26 @@ dependencies = [ "secp256k1-sys 0.10.1", ] +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand 0.9.2", + "secp256k1-sys 0.11.0", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4473013577ec77b4ee3668179ef1186df3146e2cf2d927bd200974c6fe60fd99" +dependencies = [ + "cc", +] + [[package]] name = "secp256k1-sys" version = "0.9.2" @@ -20978,6 +21566,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -20999,23 +21596,35 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", - "core-foundation", + "bitflags 2.9.3", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +dependencies = [ + "bitflags 2.9.3", + "core-foundation 0.10.1", "core-foundation-sys", "libc", - "num-bigint", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -21045,14 +21654,14 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser 0.10.3", ] [[package]] name = "semver" -version = "1.0.18" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] @@ -21065,9 +21674,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -21108,9 +21717,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" dependencies = [ "serde", ] @@ -21121,20 +21730,20 @@ version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] @@ -21148,9 +21757,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "indexmap", "itoa", @@ -21161,16 +21770,25 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ @@ -21182,9 +21800,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", @@ -21198,14 +21816,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -21241,7 +21859,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -21265,14 +21883,14 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -21301,9 +21919,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -21314,30 +21932,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -21345,9 +21953,9 @@ dependencies = [ [[package]] name = "simba" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" dependencies = [ "approx", "num-complex", @@ -21362,7 +21970,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", ] [[package]] @@ -21385,12 +21993,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slice-group-by" @@ -21410,9 +22015,9 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -21430,9 +22035,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -21448,8 +22053,8 @@ dependencies = [ "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-net 1.7.0", - "async-process 1.7.0", + "async-net 1.8.0", + "async-process 1.8.1", "blocking", "futures-lite 1.13.0", ] @@ -21460,24 +22065,15 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.3.0", + "async-channel 2.5.0", "async-executor", - "async-fs 2.1.2", - "async-io 2.3.3", - "async-lock 3.4.0", + "async-fs 2.1.3", + "async-io 2.5.0", + "async-lock 3.4.1", "async-net 2.0.0", - "async-process 2.3.0", + "async-process 2.4.0", "blocking", - "futures-lite 2.3.0", -] - -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", + "futures-lite 2.6.1", ] [[package]] @@ -21495,7 +22091,7 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.17", + "derive_more 0.99.20", "ed25519-zebra", "either", "event-listener 2.5.3", @@ -21522,7 +22118,7 @@ dependencies = [ "schnorrkel 0.10.2", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "siphasher 0.3.11", "slab", @@ -21541,7 +22137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "966e72d77a3b2171bb7461d0cb91f43670c63558c62d7cf42809cae6c8b6b818" dependencies = [ "arrayvec 0.7.6", - "async-lock 3.4.0", + "async-lock 3.4.1", "atomic-take", "base64 0.22.1", "bip39", @@ -21549,12 +22145,12 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.17", + "derive_more 0.99.20", "ed25519-zebra", "either", - "event-listener 5.3.1", + "event-listener 5.4.1", "fnv", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "futures-util", "hashbrown 0.14.5", "hex", @@ -21573,15 +22169,15 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd 0.6.0", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "siphasher 1.0.1", "slab", "smallvec", - "soketto 0.8.0", + "soketto 0.8.1", "twox-hash 1.6.3", "wasmi 0.32.3", "x25519-dalek", @@ -21595,7 +22191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16e5723359f0048bf64bfdfba64e5732a56847d42c4fd3fe56f18280c813413" dependencies = [ "arrayvec 0.7.6", - "async-lock 3.4.0", + "async-lock 3.4.1", "atomic-take", "base64 0.22.1", "bip39", @@ -21606,11 +22202,11 @@ dependencies = [ "derive_more 2.0.1", "ed25519-zebra", "either", - "event-listener 5.3.1", + "event-listener 5.4.1", "fnv", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "futures-util", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "hex", "hmac 0.12.1", "itertools 0.14.0", @@ -21627,15 +22223,15 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd 0.8.1", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "siphasher 1.0.1", "slab", "smallvec", - "soketto 0.8.0", + "soketto 0.8.1", "twox-hash 2.1.1", "wasmi 0.40.0", "x25519-dalek", @@ -21652,7 +22248,7 @@ dependencies = [ "async-lock 2.8.0", "base64 0.21.7", "blake2-rfc", - "derive_more 0.99.17", + "derive_more 0.99.20", "either", "event-listener 2.5.3", "fnv", @@ -21663,9 +22259,9 @@ dependencies = [ "hex", "itertools 0.11.0", "log", - "lru 0.11.0", + "lru 0.11.1", "no-std-net", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "rand_chacha 0.3.1", @@ -21684,24 +22280,24 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a33b06891f687909632ce6a4e3fd7677b24df930365af3d0bcb078310129f3f" dependencies = [ - "async-channel 2.3.0", - "async-lock 3.4.0", + "async-channel 2.5.0", + "async-lock 3.4.1", "base64 0.22.1", "blake2-rfc", "bs58", - "derive_more 0.99.17", + "derive_more 0.99.20", "either", - "event-listener 5.3.1", + "event-listener 5.4.1", "fnv", "futures-channel", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "futures-util", "hashbrown 0.14.5", "hex", "itertools 0.13.0", "log", - "lru 0.12.3", - "parking_lot 0.12.3", + "lru 0.12.5", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "rand_chacha 0.3.1", @@ -21720,24 +22316,24 @@ version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bba9e591716567d704a8252feeb2f1261a286e1e2cbdd4e49e9197c34a14e2" dependencies = [ - "async-channel 2.3.0", - "async-lock 3.4.0", + "async-channel 2.5.0", + "async-lock 3.4.1", "base64 0.22.1", "blake2-rfc", "bs58", "derive_more 2.0.1", "either", - "event-listener 5.3.1", + "event-listener 5.4.1", "fnv", "futures-channel", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "futures-util", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "hex", "itertools 0.14.0", "log", - "lru 0.12.3", - "parking_lot 0.12.3", + "lru 0.12.5", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "rand_chacha 0.3.1", @@ -21752,9 +22348,9 @@ dependencies = [ [[package]] name = "snap" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snow" @@ -21767,10 +22363,10 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek", "rand_core 0.6.4", - "ring 0.17.8", - "rustc_version 0.4.0", - "sha2 0.10.8", - "subtle 2.5.0", + "ring 0.17.14", + "rustc_version 0.4.1", + "sha2 0.10.9", + "subtle 2.6.1", ] [[package]] @@ -21875,7 +22471,7 @@ dependencies = [ name = "snowbridge-merkle-tree" version = "0.2.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "hex", "hex-literal", "parity-scale-codec", @@ -22304,9 +22900,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -22314,14 +22910,24 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "soketto" version = "0.7.1" @@ -22339,14 +22945,14 @@ dependencies = [ [[package]] name = "soketto" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ "base64 0.22.1", "bytes", "futures", - "http 1.1.0", + "http 1.3.1", "httparse", "log", "rand 0.8.5", @@ -22453,7 +23059,7 @@ dependencies = [ "sp-test-primitives", "sp-trie", "sp-version", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -22464,10 +23070,10 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -22571,7 +23177,7 @@ version = "28.0.0" dependencies = [ "futures", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "schnellru", "sp-api", "sp-consensus", @@ -22579,7 +23185,7 @@ dependencies = [ "sp-database", "sp-runtime", "sp-state-machine", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", ] @@ -22593,7 +23199,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -22632,7 +23238,7 @@ dependencies = [ name = "sp-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "parity-scale-codec", "scale-info", "serde", @@ -22704,7 +23310,7 @@ name = "sp-core" version = "28.0.0" dependencies = [ "ark-vrf", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections 0.3.2", @@ -22723,18 +23329,18 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "paste", "primitive-types 0.13.1", "rand 0.8.5", "regex", "scale-info", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "secp256k1 0.28.2", "secrecy 0.8.0", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sp-crypto-hashing 0.1.0", "sp-debug-derive 14.0.0", "sp-externalities 0.25.0", @@ -22742,7 +23348,7 @@ dependencies = [ "sp-storage 19.0.0", "ss58-registry", "substrate-bip39 0.4.7", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "w3f-bls", "zeroize", @@ -22755,10 +23361,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cdbb58c21e6b27f2aadf3ff0c8b20a8ead13b9dfe63f46717fd59334517f3b4" dependencies = [ "ark-vrf", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bitflags 1.3.2", "blake2 0.10.6", - "bounded-collections 0.2.3", + "bounded-collections 0.2.4", "bs58", "dyn-clonable", "ed25519-zebra", @@ -22773,12 +23379,12 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "paste", "primitive-types 0.13.1", "rand 0.8.5", "scale-info", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "secp256k1 0.28.2", "secrecy 0.8.0", "serde", @@ -22790,7 +23396,7 @@ dependencies = [ "sp-storage 22.0.0", "ss58-registry", "substrate-bip39 0.6.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "w3f-bls", "zeroize", @@ -22846,7 +23452,7 @@ dependencies = [ "byteorder", "criterion", "digest 0.10.7", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "sp-crypto-hashing-proc-macro", "twox-hash 1.6.3", @@ -22861,7 +23467,7 @@ dependencies = [ "blake2b_simd", "byteorder", "digest 0.10.7", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "twox-hash 1.6.3", ] @@ -22872,7 +23478,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.40", "sp-crypto-hashing 0.1.0", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -22880,16 +23486,16 @@ name = "sp-database" version = "10.0.0" dependencies = [ "kvdb", - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] name = "sp-debug-derive" version = "14.0.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -22898,9 +23504,9 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -22944,7 +23550,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -22986,7 +23592,7 @@ name = "sp-keystore" version = "0.34.0" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sp-core 28.0.0", "sp-externalities 0.25.0", ] @@ -22995,7 +23601,7 @@ dependencies = [ name = "sp-maybe-compressed-blob" version = "11.0.0" dependencies = [ - "thiserror 1.0.65", + "thiserror 1.0.69", "zstd 0.12.4", ] @@ -23022,7 +23628,7 @@ dependencies = [ name = "sp-mmr-primitives" version = "26.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "log", "parity-scale-codec", "polkadot-ckb-merkle-mountain-range", @@ -23032,7 +23638,7 @@ dependencies = [ "sp-core 28.0.0", "sp-debug-derive 14.0.0", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -23168,10 +23774,10 @@ version = "17.0.0" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -23182,10 +23788,10 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -23255,12 +23861,12 @@ name = "sp-state-machine" version = "0.35.0" dependencies = [ "arbitrary", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_matches", "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pretty_assertions", "rand 0.8.5", "smallvec", @@ -23269,7 +23875,7 @@ dependencies = [ "sp-panic-handler", "sp-runtime", "sp-trie", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "trie-db", ] @@ -23285,7 +23891,7 @@ dependencies = [ "parity-scale-codec", "rand 0.8.5", "scale-info", - "sha2 0.10.8", + "sha2 0.10.9", "sp-api", "sp-application-crypto", "sp-core 28.0.0", @@ -23293,7 +23899,7 @@ dependencies = [ "sp-externalities 0.25.0", "sp-runtime", "sp-runtime-interface 24.0.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "x25519-dalek", ] @@ -23351,7 +23957,7 @@ dependencies = [ "parity-scale-codec", "sp-inherents", "sp-runtime", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -23362,7 +23968,7 @@ dependencies = [ "regex", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -23374,7 +23980,7 @@ dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -23403,15 +24009,15 @@ name = "sp-trie" version = "29.0.0" dependencies = [ "ahash", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "criterion", - "foldhash", + "foldhash 0.1.5", "hash-db", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "rand 0.8.5", "scale-info", "schnellru", @@ -23419,7 +24025,7 @@ dependencies = [ "sp-externalities 0.25.0", "sp-runtime", "substrate-prometheus-endpoint", - "thiserror 1.0.65", + "thiserror 1.0.69", "tracing", "trie-bench", "trie-db", @@ -23440,7 +24046,7 @@ dependencies = [ "sp-runtime", "sp-std 14.0.0", "sp-version-proc-macro", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -23449,10 +24055,10 @@ version = "13.0.0" dependencies = [ "parity-scale-codec", "proc-macro-warning", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "sp-version", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -23485,7 +24091,7 @@ dependencies = [ "bounded-collections 0.3.2", "parity-scale-codec", "scale-info", - "schemars", + "schemars 0.8.22", "serde", "smallvec", "sp-arithmetic", @@ -23519,30 +24125,29 @@ dependencies = [ ] [[package]] -name = "spki" -version = "0.7.2" +name = "spinning_top" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ - "base64ct", - "der", + "lock_api", ] [[package]] -name = "sqlformat" -version = "0.2.6" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ - "nom 7.1.3", - "unicode_categories", + "base64ct", + "der", ] [[package]] name = "sqlx" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" dependencies = [ "sqlx-core", "sqlx-macros", @@ -23553,37 +24158,32 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "atoi", - "byteorder", + "base64 0.22.1", "bytes", "crc", "crossbeam-queue", "either", - "event-listener 5.3.1", - "futures-channel", + "event-listener 5.4.1", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.14.5", - "hashlink 0.9.1", - "hex", + "hashbrown 0.15.5", + "hashlink 0.10.0", "indexmap", "log", "memchr", "once_cell", - "paste", "percent-encoding", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", - "sqlformat", - "thiserror 1.0.65", + "thiserror 2.0.16", "tokio", "tokio-stream", "tracing", @@ -23592,52 +24192,51 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "sqlx-core", "sqlx-macros-core", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "sqlx-macros-core" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" dependencies = [ "dotenvy", "either", "heck 0.5.0", "hex", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.98", - "tempfile", + "syn 2.0.106", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.9.3", "byteorder", "bytes", "crc", @@ -23662,31 +24261,30 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.65", + "thiserror 2.0.16", "tracing", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.9.3", "byteorder", "crc", "dotenvy", "etcetera", "futures-channel", "futures-core", - "futures-io", "futures-util", "hex", "hkdf", @@ -23700,20 +24298,20 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.65", + "thiserror 2.0.16", "tracing", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" dependencies = [ "atoi", "flume", @@ -23728,23 +24326,24 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", + "thiserror 2.0.16", "tracing", "url", ] [[package]] name = "ss58-registry" -version = "1.43.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" +checksum = "19409f13998e55816d1c728395af0b52ec066206341d939e22e7766df9b494b8" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde", "serde_json", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] @@ -23765,7 +24364,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -23795,7 +24394,7 @@ dependencies = [ name = "staging-node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "assert_cmd", "clap", "clap_complete", @@ -23817,7 +24416,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "soketto 0.8.0", + "soketto 0.8.1", "sp-keyring", "staging-node-inspect", "substrate-cli-test-utils", @@ -23842,7 +24441,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-statement-store", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -23865,7 +24464,7 @@ version = "2.0.0" name = "staging-xcm" version = "7.0.1" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bounded-collections 0.3.2", "derive-where", "environmental", @@ -23874,7 +24473,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "schemars", + "schemars 0.8.22", "serde", "sp-io", "sp-runtime", @@ -23943,28 +24542,28 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "static_init" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" +checksum = "8bae1df58c5fea7502e8e352ec26b5579f6178e1fdb311e088580c980dee25ed" dependencies = [ "bitflags 1.3.2", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "libc", - "parking_lot 0.11.2", - "parking_lot_core 0.8.6", + "parking_lot 0.12.4", + "parking_lot_core 0.9.11", "static_init_macro", "winapi", ] [[package]] name = "static_init_macro" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" +checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f" dependencies = [ "cfg_aliases 0.1.1", "memchr", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -24022,7 +24621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "rustversion", "syn 1.0.109", @@ -24035,10 +24634,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "rustversion", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -24057,8 +24656,8 @@ dependencies = [ "parity-bip39", "pbkdf2", "rustc-hex", - "schnorrkel 0.11.4", - "sha2 0.10.8", + "schnorrkel 0.11.5", + "sha2 0.10.9", "zeroize", ] @@ -24070,8 +24669,8 @@ checksum = "ca58ffd742f693dc13d69bdbb2e642ae239e0053f6aab3b104252892f856700a" dependencies = [ "hmac 0.12.1", "pbkdf2", - "schnorrkel 0.11.4", - "sha2 0.10.8", + "schnorrkel 0.11.5", + "sha2 0.10.9", "zeroize", ] @@ -24155,11 +24754,11 @@ name = "substrate-prometheus-endpoint" version = "0.17.0" dependencies = [ "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "log", "prometheus", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", ] @@ -24202,7 +24801,7 @@ dependencies = [ "sp-runtime", "sp-trie", "strum 0.26.3", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -24239,7 +24838,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-trait", "futures", "parity-scale-codec", @@ -24263,7 +24862,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "frame-executive", "frame-metadata-hash-extension", "frame-support", @@ -24339,13 +24938,13 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", "sp-runtime", "substrate-test-runtime-client", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -24369,8 +24968,8 @@ dependencies = [ "hex", "jsonrpsee", "parity-scale-codec", - "parking_lot 0.12.3", - "rand 0.9.0", + "parking_lot 0.12.4", + "rand 0.9.2", "serde", "serde_json", "subxt 0.41.0", @@ -24378,19 +24977,19 @@ dependencies = [ "subxt-rpcs 0.41.0", "subxt-signer 0.41.0", "termplot", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", "tokio", "tokio-util", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] name = "substrate-wasm-builder" version = "17.0.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "build-helper", "cargo_metadata", "console", @@ -24410,7 +25009,7 @@ dependencies = [ "sp-version", "strum 0.26.3", "tempfile", - "toml", + "toml 0.8.23", "walkdir", "wasm-opt", ] @@ -24423,9 +25022,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "subtle-ng" @@ -24456,10 +25055,10 @@ dependencies = [ "scale-value 0.17.0", "serde", "serde_json", - "subxt-core 0.38.0", - "subxt-macro 0.38.0", - "subxt-metadata 0.38.0", - "thiserror 1.0.65", + "subxt-core 0.38.1", + "subxt-macro 0.38.1", + "subxt-metadata 0.38.1", + "thiserror 1.0.69", "tracing", "url", "web-time", @@ -24493,7 +25092,7 @@ dependencies = [ "subxt-macro 0.41.0", "subxt-metadata 0.41.0", "subxt-rpcs 0.41.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-util", "tracing", @@ -24530,7 +25129,7 @@ dependencies = [ "subxt-macro 0.43.0", "subxt-metadata 0.43.0", "subxt-rpcs 0.43.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-util", "tracing", @@ -24541,19 +25140,19 @@ dependencies = [ [[package]] name = "subxt-codegen" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cfcfb7d9589f3df0ac87c4988661cf3fb370761fcb19f2fd33104cc59daf22a" +checksum = "6550ef451c77db6e3bc7c56fb6fe1dca9398a2c8fc774b127f6a396a769b9c5b" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "scale-typegen 0.9.0", - "subxt-metadata 0.38.0", - "syn 2.0.98", - "thiserror 1.0.65", + "subxt-metadata 0.38.1", + "syn 2.0.106", + "thiserror 1.0.69", ] [[package]] @@ -24564,13 +25163,13 @@ checksum = "324c52c09919fec8c22a4b572a466878322e99fe14a9e3d50d6c3700a226ec25" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "scale-typegen 0.11.1", "subxt-metadata 0.41.0", - "syn 2.0.98", - "thiserror 2.0.12", + "syn 2.0.106", + "thiserror 2.0.16", ] [[package]] @@ -24581,20 +25180,20 @@ checksum = "1728caecd9700391e78cc30dc298221d6f5ca0ea28258a452aa76b0b7c229842" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "scale-typegen 0.11.1", "subxt-metadata 0.43.0", - "syn 2.0.98", - "thiserror 2.0.12", + "syn 2.0.106", + "thiserror 2.0.16", ] [[package]] name = "subxt-core" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea28114366780d23684bd55ab879cd04c9d4cbba3b727a3854a3eca6bf29a1a" +checksum = "cb7a1bc6c9c1724971636a66e3225a7253cdb35bb6efb81524a6c71c04f08c59" dependencies = [ "base58", "blake2 0.10.6", @@ -24615,7 +25214,7 @@ dependencies = [ "scale-value 0.17.0", "serde", "serde_json", - "subxt-metadata 0.38.0", + "subxt-metadata 0.38.1", "tracing", ] @@ -24645,7 +25244,7 @@ dependencies = [ "serde_json", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-metadata 0.41.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tracing", ] @@ -24675,7 +25274,7 @@ dependencies = [ "serde_json", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-metadata 0.43.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tracing", ] @@ -24690,7 +25289,7 @@ dependencies = [ "serde", "serde_json", "smoldot-light 0.16.2", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-stream", "tracing", @@ -24707,7 +25306,7 @@ dependencies = [ "serde", "serde_json", "smoldot-light 0.17.2", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-stream", "tracing", @@ -24715,18 +25314,18 @@ dependencies = [ [[package]] name = "subxt-macro" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228db9a5c95a6d8dc6152b4d6cdcbabc4f60821dd3f482a4f8791e022b7caadb" +checksum = "7819c5e09aae0319981ee853869f2fcd1fac4db8babd0d004c17161297aadc05" dependencies = [ "darling", "parity-scale-codec", "proc-macro-error2", "quote 1.0.40", "scale-typegen 0.9.0", - "subxt-codegen 0.38.0", - "subxt-utils-fetchmetadata 0.38.0", - "syn 2.0.98", + "subxt-codegen 0.38.1", + "subxt-utils-fetchmetadata 0.38.1", + "syn 2.0.106", ] [[package]] @@ -24742,7 +25341,7 @@ dependencies = [ "scale-typegen 0.11.1", "subxt-codegen 0.41.0", "subxt-utils-fetchmetadata 0.41.0", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -24759,14 +25358,14 @@ dependencies = [ "subxt-codegen 0.43.0", "subxt-metadata 0.43.0", "subxt-utils-fetchmetadata 0.43.0", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "subxt-metadata" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee13e6862eda035557d9a2871955306aff540d2b89c06e0a62a1136a700aed28" +checksum = "aacd4e7484fef58deaa2dcb32d94753a864b208a668c0dd0c28be1d8abeeadb2" dependencies = [ "frame-decode 0.5.1", "frame-metadata 17.0.0", @@ -24788,7 +25387,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -24803,7 +25402,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -24825,7 +25424,7 @@ dependencies = [ "serde_json", "subxt-core 0.41.0", "subxt-lightclient 0.41.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-util", "tracing", @@ -24850,7 +25449,7 @@ dependencies = [ "serde_json", "subxt-core 0.43.0", "subxt-lightclient 0.43.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio-util", "tracing", "url", @@ -24873,16 +25472,16 @@ dependencies = [ "parity-scale-codec", "pbkdf2", "regex", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "scrypt", "secp256k1 0.30.0", "secrecy 0.10.3", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-core 0.41.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "zeroize", ] @@ -24901,28 +25500,28 @@ dependencies = [ "parity-scale-codec", "pbkdf2", "regex", - "schnorrkel 0.11.4", + "schnorrkel 0.11.5", "scrypt", "secp256k1 0.30.0", "secrecy 0.10.3", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-core 0.43.0", - "thiserror 2.0.12", + "thiserror 2.0.16", "zeroize", ] [[package]] name = "subxt-utils-fetchmetadata" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082b17a86e3c3fe45d858d94d68f6b5247caace193dad6201688f24db8ba9bb" +checksum = "a3c53bc3eeaacc143a2f29ace4082edd2edaccab37b69ad20befba9fb00fdb3d" dependencies = [ "hex", "parity-scale-codec", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -24933,7 +25532,7 @@ checksum = "fc868b55fe2303788dc7703457af390111940c3da4714b510983284501780ed5" dependencies = [ "hex", "parity-scale-codec", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -24944,20 +25543,20 @@ checksum = "8c4fb8fd6b16ecd3537a29d70699f329a68c1e47f70ed1a46d64f76719146563" dependencies = [ "hex", "parity-scale-codec", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "sval" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1" +checksum = "7cc9739f56c5d0c44a5ed45473ec868af02eb896af8c05f616673a31e1d1bb09" [[package]] name = "sval_buffer" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028" +checksum = "f39b07436a8c271b34dad5070c634d1d3d76d6776e938ee97b4a66a5e8003d0b" dependencies = [ "sval", "sval_ref", @@ -24965,18 +25564,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf" +checksum = "ffcb072d857431bf885580dacecf05ed987bac931230736739a79051dbf3499b" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326" +checksum = "3f214f427ad94a553e5ca5514c95c6be84667cbc5568cce957f03f3477d03d5c" dependencies = [ "itoa", "ryu", @@ -24985,53 +25584,63 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d" +checksum = "389ed34b32e638dec9a99c8ac92d0aa1220d40041026b625474c2b6a4d6f4feb" dependencies = [ "itoa", "ryu", "sval", ] +[[package]] +name = "sval_nested" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14bae8fcb2f24fee2c42c1f19037707f7c9a29a0cda936d2188d48a961c4bb2a" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + [[package]] name = "sval_ref" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c" +checksum = "2a4eaea3821d3046dcba81d4b8489421da42961889902342691fb7eab491d79e" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.6.1" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046" +checksum = "172dd4aa8cb3b45c8ac8f3b4111d644cd26938b0643ede8f93070812b87fb339" dependencies = [ "serde", "sval", - "sval_buffer", - "sval_fmt", + "sval_nested", ] [[package]] name = "symbolic-common" -version = "12.14.1" +version = "12.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66135c8273581acaab470356f808a1c74a707fe7ec24728af019d7247e089e71" +checksum = "9da12f8fecbbeaa1ee62c1d50dc656407e007c3ee7b2a41afce4b5089eaef15e" dependencies = [ "debugid", - "memmap2 0.9.3", + "memmap2 0.9.8", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "12.14.1" +version = "12.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bcacd080282a72e795864660b148392af7babd75691d5ae9a3b77e29c98c77" +checksum = "6fd35afe0ef9d35d3dcd41c67ddf882fc832a387221338153b7cd685a105495c" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -25055,39 +25664,39 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.98" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "unicode-ident", ] [[package]] name = "syn-solidity" -version = "1.1.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" +checksum = "a0b198d366dbec045acfcd97295eb653a7a2b40e4dc764ef1e79aafcad439d3c" dependencies = [ "paste", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -25098,28 +25707,28 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "sysinfo" -version = "0.30.5" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" dependencies = [ "cfg-if", "core-foundation-sys", @@ -25130,36 +25739,15 @@ dependencies = [ "windows 0.52.0", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys 0.5.0", -] - [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "system-configuration-sys 0.6.0", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", + "bitflags 2.9.3", + "core-foundation 0.9.4", + "system-configuration-sys", ] [[package]] @@ -25186,9 +25774,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.40" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -25203,21 +25791,21 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "target-triple" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" +checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ - "cfg-if", "fastrand 2.3.0", + "getrandom 0.3.3", "once_cell", - "rustix 0.38.42", - "windows-sys 0.59.0", + "rustix 1.0.8", + "windows-sys 0.60.2", ] [[package]] @@ -25225,28 +25813,28 @@ name = "template-zombienet-tests" version = "0.0.0" dependencies = [ "anyhow", - "env_logger 0.11.3", + "env_logger 0.11.8", "tokio", "zombienet-sdk", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 0.38.42", - "windows-sys 0.48.0", + "rustix 1.0.8", + "windows-sys 0.60.2", ] [[package]] @@ -25260,9 +25848,9 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-log" @@ -25270,9 +25858,9 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b" dependencies = [ - "env_logger 0.11.3", + "env_logger 0.11.8", "test-log-macros", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -25281,9 +25869,9 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -25398,62 +25986,62 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.65", + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] name = "thiserror-core" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" dependencies = [ "thiserror-core-impl", ] [[package]] name = "thiserror-core-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -25464,12 +26052,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -25514,9 +26101,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -25531,15 +26118,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -25556,9 +26143,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -25576,9 +26163,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -25591,27 +26178,29 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.9", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "tokio-io-timeout" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" dependencies = [ "pin-project-lite", "tokio", @@ -25623,9 +26212,9 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -25655,26 +26244,25 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.7", + "rustls 0.21.12", "tokio", ] [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.18", - "rustls-pki-types", + "rustls 0.23.31", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -25727,19 +26315,19 @@ checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" dependencies = [ "futures-util", "log", - "rustls 0.23.18", - "rustls-native-certs 0.8.0", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.2", "tungstenite 0.27.0", ] [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -25752,21 +26340,54 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow 0.7.13", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.22", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ "serde", ] @@ -25778,34 +26399,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", - "toml_datetime", - "winnow 0.5.15", + "toml_datetime 0.6.11", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", - "toml_datetime", - "winnow 0.5.15", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.13", ] [[package]] -name = "toml_edit" -version = "0.22.22" +name = "toml_parser" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.6.18", + "winnow 0.7.13", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tower" version = "0.4.13" @@ -25823,6 +26455,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.4.4" @@ -25830,12 +26477,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "base64 0.21.7", - "bitflags 2.6.0", + "bitflags 2.9.3", "bytes", "futures-core", "futures-util", - "http 0.2.9", - "http-body 0.4.5", + "http 0.2.12", + "http-body 0.4.6", "http-range-header", "mime", "pin-project-lite", @@ -25850,33 +26497,51 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", "bytes", - "http 1.1.0", - "http-body 1.0.0", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", "pin-project-lite", "tower-layer", "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.3", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -25886,20 +26551,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -25931,10 +26596,10 @@ version = "5.0.0" dependencies = [ "assert_matches", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.3.0", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -25950,15 +26615,24 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "chrono", "matchers", "nu-ansi-term", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "regex", "sharded-slab", "smallvec", @@ -26018,15 +26692,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.103" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b812699e0c4f813b872b373a4471717d9eb550da14b311058a4d9cf4173cbca6" +checksum = "32e257d7246e7a9fd015fb0b28b330a8d4142151a33f03e6a497754f4b1f6a8e" dependencies = [ "dissimilar", "glob", @@ -26035,7 +26709,7 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml", + "toml 0.9.5", ] [[package]] @@ -26053,12 +26727,12 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.9", + "http 0.2.12", "httparse", "log", "rand 0.8.5", "sha1", - "thiserror 1.0.65", + "thiserror 1.0.69", "url", "utf-8", ] @@ -26071,12 +26745,12 @@ checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ "bytes", "data-encoding", - "http 1.1.0", + "http 1.3.1", "httparse", "log", - "rand 0.9.0", + "rand 0.9.2", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.16", "utf-8", ] @@ -26088,14 +26762,14 @@ checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ "bytes", "data-encoding", - "http 1.1.0", + "http 1.3.1", "httparse", "log", - "rand 0.9.0", - "rustls 0.23.18", + "rand 0.9.2", + "rustls 0.23.31", "rustls-pki-types", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", "utf-8", ] @@ -26124,17 +26798,23 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -26168,15 +26848,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -26195,21 +26875,15 @@ checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode-width" -version = "0.1.10" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "unicode-xid" @@ -26219,15 +26893,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "unicode_categories" -version = "0.1.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -26236,7 +26904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -26281,12 +26949,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", "serde", ] @@ -26297,12 +26965,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -26311,30 +26973,32 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.4.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" -version = "1.8.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec26a25bd6fca441cdd0f769fd7f891bae119f996de31f86a5eddccef54c1d" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -26342,9 +27006,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.8.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead5b693d906686203f19a49e88c477fb8c15798b68cf72f60b4b5521b4ad891" +checksum = "35540706617d373b118d550d41f5dfe0b78a0c195dc13c6815e92e2638432306" dependencies = [ "erased-serde", "serde", @@ -26353,9 +27017,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.8.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9d0f4a816370c3a0d7d82d603b62198af17675b12fe5e91de6b47ceb505882" +checksum = "6fe7e140a2658cc16f7ee7a86e413e803fc8f9b5127adc8755c19f9fefa63a52" dependencies = [ "sval", "sval_buffer", @@ -26391,9 +27055,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -26418,7 +27082,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "zeroize", ] @@ -26474,18 +27138,18 @@ dependencies = [ [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -26508,15 +27172,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -26527,14 +27191,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" +[[package]] +name = "wasix" +version = "0.12.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d" +dependencies = [ + "wasi 0.11.1+wasi-snapshot-preview1", +] + [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "serde", "serde_json", "wasm-bindgen-macro", @@ -26542,36 +27216,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote 1.0.40", "wasm-bindgen-macro-support", @@ -26579,40 +27253,44 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a" dependencies = [ - "leb128", + "leb128fmt", + "wasmparser 0.235.0", ] [[package]] name = "wasm-encoder" -version = "0.235.0" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a" +checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c" dependencies = [ "leb128fmt", - "wasmparser 0.235.0", + "wasmparser 0.237.0", ] [[package]] @@ -26626,16 +27304,16 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.116.0" +version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" dependencies = [ "anyhow", "libc", "strum 0.24.1", "strum_macros 0.24.3", "tempfile", - "thiserror 1.0.65", + "thiserror 1.0.69", "wasm-opt-cxx-sys", "wasm-opt-sys", ] @@ -26797,7 +27475,7 @@ version = "0.221.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", ] [[package]] @@ -26806,13 +27484,24 @@ version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ - "bitflags 2.6.0", - "hashbrown 0.15.3", + "bitflags 2.9.3", + "hashbrown 0.15.5", "indexmap", - "semver 1.0.18", + "semver 1.0.26", "serde", ] +[[package]] +name = "wasmparser" +version = "0.237.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" +dependencies = [ + "bitflags 2.9.3", + "indexmap", + "semver 1.0.26", +] + [[package]] name = "wasmparser-nostd" version = "0.100.2" @@ -26839,20 +27528,20 @@ version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe976922a16af3b0d67172c473d1fd4f1aa5d0af9c8ba6538c741f3af686f4" dependencies = [ - "addr2line 0.24.2", + "addr2line", "anyhow", - "bitflags 2.6.0", + "bitflags 2.9.3", "bumpalo", "cc", "cfg-if", - "gimli 0.31.1", - "hashbrown 0.15.3", + "gimli", + "hashbrown 0.15.5", "indexmap", "libc", "log", "mach2", "memfd", - "object 0.36.7", + "object", "once_cell", "postcard", "pulley-interpreter", @@ -26887,10 +27576,10 @@ dependencies = [ "cpp_demangle", "cranelift-bitset", "cranelift-entity", - "gimli 0.31.1", + "gimli", "indexmap", "log", - "object 0.36.7", + "object", "postcard", "rustc-demangle", "serde", @@ -26925,8 +27614,8 @@ dependencies = [ "rustix 1.0.8", "serde", "serde_derive", - "sha2 0.10.8", - "toml", + "sha2 0.10.9", + "toml 0.8.23", "windows-sys 0.59.0", "zstd 0.13.3", ] @@ -26944,14 +27633,14 @@ dependencies = [ "cranelift-entity", "cranelift-frontend", "cranelift-native", - "gimli 0.31.1", + "gimli", "itertools 0.14.0", "log", - "object 0.36.7", + "object", "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 2.0.12", + "thiserror 2.0.16", "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-math", @@ -27011,7 +27700,7 @@ dependencies = [ "cfg-if", "cranelift-codegen", "log", - "object 0.36.7", + "object", ] [[package]] @@ -27020,9 +27709,9 @@ version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "342b0466f92b7217a4de9e114175fedee1907028567d2548bcd42f71a8b5b016" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -27033,8 +27722,8 @@ checksum = "2012e7384c25b91aab2f1b6a1e1cbab9d0f199bbea06cc873597a3f047f05730" dependencies = [ "anyhow", "cranelift-codegen", - "gimli 0.31.1", - "object 0.36.7", + "gimli", + "object", "target-lexicon", "wasmparser 0.235.0", "wasmtime-environ", @@ -27044,30 +27733,31 @@ dependencies = [ [[package]] name = "wast" -version = "63.0.0" +version = "237.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" +checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767" dependencies = [ - "leb128", + "bumpalo", + "leb128fmt", "memchr", - "unicode-width 0.1.10", - "wasm-encoder 0.31.1", + "unicode-width", + "wasm-encoder 0.237.0", ] [[package]] name = "wat" -version = "1.0.70" +version = "1.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" +checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -27083,17 +27773,35 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.2", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] @@ -27257,19 +27965,19 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.2" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall 0.5.8", + "libredox", "wasite", ] [[package]] name = "wide" -version = "0.7.11" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" dependencies = [ "bytemuck", "safe_arch", @@ -27277,9 +27985,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" [[package]] name = "winapi" @@ -27299,11 +28007,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "winapi", + "windows-sys 0.60.2", ] [[package]] @@ -27321,11 +28029,11 @@ dependencies = [ "anyhow", "cranelift-assembler-x64", "cranelift-codegen", - "gimli 0.31.1", + "gimli", "regalloc2 0.12.2", "smallvec", "target-lexicon", - "thiserror 2.0.12", + "thiserror 2.0.16", "wasmparser 0.235.0", "wasmtime-environ", "wasmtime-internal-cranelift", @@ -27334,130 +28042,172 @@ dependencies = [ [[package]] name = "windows" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-targets 0.48.5", + "windows-core 0.52.0", + "windows-targets 0.52.6", ] [[package]] name = "windows" -version = "0.51.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" dependencies = [ - "windows-core 0.51.1", - "windows-targets 0.48.5", + "windows-core 0.53.0", + "windows-targets 0.52.6", ] [[package]] name = "windows" -version = "0.52.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link", + "windows-numerics", ] [[package]] -name = "windows" -version = "0.58.0" +name = "windows-collections" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-core 0.61.2", ] [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" dependencies = [ + "windows-result 0.1.2", "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-result", + "windows-link", + "windows-result 0.3.4", "windows-strings", - "windows-targets 0.52.6", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] -name = "windows-registry" +name = "windows-numerics" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link", +] + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-result", + "windows-link", + "windows-result 0.3.4", "windows-strings", - "windows-targets 0.52.6", ] [[package]] name = "windows-result" -version = "0.2.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-result", - "windows-targets 0.52.6", + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -27487,6 +28237,30 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -27511,13 +28285,45 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -27530,6 +28336,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -27542,6 +28360,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -27554,12 +28384,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -27572,6 +28420,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -27584,6 +28444,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -27596,6 +28468,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -27609,28 +28493,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.5.15" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" -dependencies = [ - "memchr", -] +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.6.18" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -27647,24 +28528,18 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.3", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -27693,14 +28568,14 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", "data-encoding", "der-parser 9.0.0", "lazy_static", "nom 7.1.3", - "oid-registry 0.7.0", + "oid-registry 0.7.1", "rusticata-macros", - "thiserror 1.0.65", + "thiserror 1.0.69", "time", ] @@ -27710,24 +28585,25 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" dependencies = [ - "asn1-rs 0.7.0", + "asn1-rs 0.7.1", "data-encoding", "der-parser 10.0.0", "lazy_static", "nom 7.1.3", "oid-registry 0.8.1", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] [[package]] name = "xattr" -version = "1.0.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" dependencies = [ "libc", + "rustix 1.0.8", ] [[package]] @@ -27756,7 +28632,7 @@ dependencies = [ name = "xcm-emulator" version = "0.5.0" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "cumulus-pallet-parachain-system", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", @@ -27815,10 +28691,10 @@ version = "7.0.0" dependencies = [ "Inflector", "frame-support", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "staging-xcm", - "syn 2.0.98", + "syn 2.0.106", "trybuild", ] @@ -27919,9 +28795,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" [[package]] name = "xmltree" @@ -27941,7 +28817,7 @@ dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", "rand 0.8.5", "static_assertions", @@ -27956,18 +28832,18 @@ dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project", - "rand 0.9.0", + "rand 0.9.2", "static_assertions", "web-time", ] [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yap" @@ -28047,9 +28923,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -28059,75 +28935,55 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "synstructure 0.13.1", + "syn 2.0.106", + "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "zerocopy-derive 0.7.32", -] - -[[package]] -name = "zerocopy" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c" -dependencies = [ - "zerocopy-derive 0.8.20", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" -dependencies = [ - "proc-macro2 1.0.95", - "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", - "synstructure 0.13.1", + "syn 2.0.106", + "synstructure 0.13.2", ] [[package]] @@ -28145,16 +29001,27 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -28163,13 +29030,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", - "syn 2.0.98", + "syn 2.0.106", ] [[package]] @@ -28180,7 +29047,7 @@ dependencies = [ "parity-scale-codec", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-tungstenite 0.26.2", "tracing-gum", @@ -28194,14 +29061,14 @@ checksum = "a5e93ea881757b3d3015d9dd41e04ceafb4d9747c5edd36a3f772c3137cec142" dependencies = [ "anyhow", "lazy_static", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "regex", "reqwest", "serde", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", - "toml", + "toml 0.8.23", "tracing", "url", "zombienet-support", @@ -28221,17 +29088,17 @@ dependencies = [ "hex", "libp2p", "libsecp256k1", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "rand 0.8.5", "regex", "reqwest", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sp-core 36.1.0", "subxt 0.43.0", "subxt-signer 0.43.0", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing", "uuid", @@ -28249,7 +29116,7 @@ checksum = "fe24a05a4dda190039120ca480b729c5953f1aa52edc2caa1990b06281b71b93" dependencies = [ "pest", "pest_derive", - "thiserror 1.0.65", + "thiserror 1.0.69", ] [[package]] @@ -28271,9 +29138,9 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "sha2 0.10.8", + "sha2 0.10.9", "tar", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -28316,7 +29183,7 @@ dependencies = [ "regex", "reqwest", "serde_json", - "thiserror 1.0.65", + "thiserror 1.0.69", "tokio", "tracing", "uuid", diff --git a/Cargo.toml b/Cargo.toml index ae54190d18a9e..76e9822ad23f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -928,7 +928,7 @@ node-rpc = { path = "substrate/bin/node/rpc" } node-testing = { path = "substrate/bin/node/testing" } nohash-hasher = { version = "0.2.0" } novelpoly = { version = "2.0.0", package = "reed-solomon-novelpoly" } -num-bigint = { version = "0.4.3", default-features = false } +num-bigint = { version = "0.4.6", default-features = false } num-format = { version = "0.4.3" } num-integer = { version = "0.1.46", default-features = false } num-rational = { version = "0.4.1" } @@ -1190,6 +1190,7 @@ regex = { version = "1.10.2" } relay-substrate-client = { path = "bridges/relays/client-substrate" } relay-utils = { path = "bridges/relays/utils" } remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } +revm = { version = "27.0.2", default-features = false } ripemd = { version = "0.1.3", default-features = false } rlp = { version = "0.6.1", default-features = false } rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 8f48a3171916e..3d65d3b168293 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -85,6 +85,16 @@ const ALICE: [u8; 32] = [1u8; 32]; const BOB: [u8; 32] = [2u8; 32]; const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32]; +const ERC20_PVM: &[u8] = + include_bytes!("../../../../../../substrate/frame/revive/fixtures/erc20/erc20.polkavm"); + +const FAKE_ERC20_PVM: &[u8] = + include_bytes!("../../../../../../substrate/frame/revive/fixtures/erc20/fake_erc20.polkavm"); + +const EXPENSIVE_ERC20_PVM: &[u8] = include_bytes!( + "../../../../../../substrate/frame/revive/fixtures/erc20/expensive_erc20.polkavm" +); + parameter_types! { pub Governance: GovernanceOrigin = GovernanceOrigin::Origin(RuntimeOrigin::root()); } @@ -1670,10 +1680,7 @@ fn withdraw_and_deposit_erc20s() { assert_ok!(Revive::map_account(RuntimeOrigin::signed(sender.clone()))); assert_ok!(Revive::map_account(RuntimeOrigin::signed(beneficiary.clone()))); - let code = include_bytes!( - "../../../../../../substrate/frame/revive/fixtures/contracts/erc20.polkavm" - ) - .to_vec(); + let code = ERC20_PVM.to_vec(); let initial_amount_u256 = U256::from(1_000_000_000_000u128); let constructor_data = sol_data::Uint::<256>::abi_encode(&initial_amount_u256); @@ -1832,10 +1839,7 @@ fn smart_contract_does_not_return_bool_fails() { assert_ok!(Revive::map_account(RuntimeOrigin::signed(beneficiary.clone()))); // This contract implements the ERC20 interface for `transfer` except it returns a uint256. - let code = include_bytes!( - "../../../../../../substrate/frame/revive/fixtures/contracts/fake_erc20.polkavm" - ) - .to_vec(); + let code = FAKE_ERC20_PVM.to_vec(); let initial_amount_u256 = U256::from(1_000_000_000_000u128); let constructor_data = sol_data::Uint::<256>::abi_encode(&initial_amount_u256); @@ -1888,10 +1892,7 @@ fn expensive_erc20_runs_out_of_gas() { assert_ok!(Revive::map_account(RuntimeOrigin::signed(beneficiary.clone()))); // This contract does a lot more storage writes in `transfer`. - let code = include_bytes!( - "../../../../../../substrate/frame/revive/fixtures/contracts/expensive_erc20.polkavm" - ) - .to_vec(); + let code = EXPENSIVE_ERC20_PVM.to_vec(); let initial_amount_u256 = U256::from(1_000_000_000_000u128); let constructor_data = sol_data::Uint::<256>::abi_encode(&initial_amount_u256); diff --git a/prdoc/pr_9501.prdoc b/prdoc/pr_9501.prdoc new file mode 100644 index 0000000000000..995095f0819c0 --- /dev/null +++ b/prdoc/pr_9501.prdoc @@ -0,0 +1,13 @@ +title: '[revive] revm move existing files' +doc: +- audience: Runtime Dev + description: |- + - Move exisiting files in pallet-revive to accomodate the upcoming EVM backend + - Add solc/resolc compilation feature for fixtures +crates: +- name: asset-hub-westend-runtime + bump: patch +- name: pallet-revive + bump: patch +- name: pallet-revive-fixtures + bump: patch diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index a2be0cd34f862..6a2078dd50c43 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -35,6 +35,7 @@ polkavm = { version = "0.27.0", default-features = false } polkavm-common = { version = "0.27.0", default-features = false, features = ["alloc"] } rand = { workspace = true, optional = true } rand_pcg = { workspace = true, optional = true } +revm = { workspace = true } rlp = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true, default-features = false } @@ -98,6 +99,7 @@ std = [ "polkavm-common/std", "polkavm/std", "rand?/std", + "revm/std", "ripemd/std", "rlp/std", "scale-info/std", diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml index f1a4d7d1969f5..820a9b7952a55 100644 --- a/substrate/frame/revive/fixtures/Cargo.toml +++ b/substrate/frame/revive/fixtures/Cargo.toml @@ -16,6 +16,7 @@ exclude-from-umbrella = true workspace = true [dependencies] +alloy-core = { workspace = true, default-features = true, features = ["sol-types"], optional = true } anyhow = { workspace = true, default-features = true, optional = true } sp-core = { workspace = true, default-features = true, optional = true } sp-io = { workspace = true, default-features = true, optional = true } @@ -23,11 +24,20 @@ sp-io = { workspace = true, default-features = true, optional = true } [build-dependencies] anyhow = { workspace = true, default-features = true } cargo_metadata = { workspace = true } +hex = { workspace = true, features = ["alloc"] } pallet-revive-uapi = { workspace = true } polkavm-linker = { version = "0.27.0" } +serde_json = { workspace = true } toml = { workspace = true } [features] default = ["std"] # only when std is enabled all fixtures are available -std = ["anyhow", "sp-core", "sp-io"] +std = [ + "alloy-core", + "anyhow", + "hex/std", + "serde_json/std", + "sp-core", + "sp-io", +] diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs index ce9215a165d21..a3030a66afad0 100644 --- a/substrate/frame/revive/fixtures/build.rs +++ b/substrate/frame/revive/fixtures/build.rs @@ -30,15 +30,24 @@ const OVERRIDE_STRIP_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_STRIP"; const OVERRIDE_OPTIMIZE_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_OPTIMIZE"; /// A contract entry. +#[derive(Clone)] struct Entry { /// The path to the contract source file. path: PathBuf, + /// The type of the contract (rust or solidity). + contract_type: ContractType, +} + +#[derive(Clone, Copy)] +enum ContractType { + Rust, + Solidity, } impl Entry { /// Create a new contract entry from the given path. - fn new(path: PathBuf) -> Self { - Self { path } + fn new(path: PathBuf, contract_type: ContractType) -> Self { + Self { path, contract_type } } /// Return the path to the contract source file. @@ -55,9 +64,12 @@ impl Entry { .expect("name is valid unicode; qed") } - /// Return the name of the polkavm file. + /// Return the name of the bytecode file. fn out_filename(&self) -> String { - format!("{}.polkavm", self.name()) + match self.contract_type { + ContractType::Rust => format!("{}.polkavm", self.name()), + ContractType::Solidity => format!("{}.resolc.polkavm", self.name()), + } } } @@ -67,16 +79,18 @@ fn collect_entries(contracts_dir: &Path) -> Vec { .expect("src dir exists; qed") .filter_map(|file| { let path = file.expect("file exists; qed").path(); - if path.extension().map_or(true, |ext| ext != "rs") { - return None - } + let extension = path.extension(); - Some(Entry::new(path)) + match extension.and_then(|ext| ext.to_str()) { + Some("rs") => Some(Entry::new(path, ContractType::Rust)), + Some("sol") => Some(Entry::new(path, ContractType::Solidity)), + _ => None, + } }) .collect::>() } -/// Create a `Cargo.toml` to compile the given contract entries. +/// Create a `Cargo.toml` to compile the given Rust contract entries. fn create_cargo_toml<'a>( fixtures_dir: &Path, entries: impl Iterator, @@ -168,7 +182,7 @@ fn invoke_build(current_dir: &Path) -> Result<()> { let build_res = build_command.output().expect("failed to execute process"); if build_res.status.success() { - return Ok(()) + return Ok(()); } let stderr = String::from_utf8_lossy(&build_res.stderr); @@ -192,15 +206,166 @@ fn post_process(input_path: &Path, output_path: &Path) -> Result<()> { Ok(()) } -/// Write the compiled contracts to the given output directory. +/// Compile a Solidity contract using standard JSON interface. +fn compile_with_standard_json( + compiler: &str, + contracts_dir: &Path, + solidity_entries: &[&Entry], +) -> Result { + let mut input_json = serde_json::json!({ + "language": "Solidity", + "sources": {}, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": + + serde_json::json!({ + "*": { + "*": ["evm.bytecode"] + } + }), + + } + }); + + // Add all Solidity files to the input + for entry in solidity_entries { + let source_code = fs::read_to_string(entry.path()) + .with_context(|| format!("Failed to read Solidity source: {}", entry.path()))?; + + let file_key = entry.path().split('/').last().unwrap_or(entry.name()); + input_json["sources"][file_key] = serde_json::json!({ + "content": source_code + }); + } + + let compiler_output = Command::new(compiler) + .current_dir(contracts_dir) + .arg("--standard-json") + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn() + .with_context(|| { + format!("Failed to execute {}. Make sure {} is installed.", compiler, compiler) + })?; + + let mut stdin = compiler_output.stdin.as_ref().unwrap(); + stdin + .write_all(input_json.to_string().as_bytes()) + .with_context(|| format!("Failed to write to {} stdin", compiler))?; + let _ = stdin; + + let compiler_result = compiler_output + .wait_with_output() + .with_context(|| format!("Failed to wait for {} output", compiler))?; + + if !compiler_result.status.success() { + let stderr = String::from_utf8_lossy(&compiler_result.stderr); + bail!("{} compilation failed: {}", compiler, stderr); + } + + // Parse JSON output + let compiler_json: serde_json::Value = serde_json::from_slice(&compiler_result.stdout) + .with_context(|| format!("Failed to parse {} JSON output", compiler))?; + + // Abort on errors + if let Some(errors) = compiler_json.get("errors") { + if errors + .as_array() + .unwrap() + .iter() + .any(|object| object.get("severity").unwrap().as_str().unwrap() == "error") + { + bail!( + "failed to compile the Solidity fixtures: {}", + serde_json::to_string_pretty(errors)? + ); + } + } + + Ok(compiler_json) +} + +/// Extract bytecode from compiler JSON output and write binary files. +fn extract_and_write_bytecode( + compiler_json: &serde_json::Value, + out_dir: &Path, + file_suffix: &str, +) -> Result<()> { + if let Some(contracts) = compiler_json["contracts"].as_object() { + for (_file_key, file_contracts) in contracts { + if let Some(contract_map) = file_contracts.as_object() { + for (contract_name, contract_data) in contract_map { + // Navigate through the JSON path to find the bytecode + let mut current = contract_data; + for path_segment in ["evm", "bytecode", "object"] { + if let Some(next) = current.get(path_segment) { + current = next; + } else { + // Skip if path doesn't exist (e.g., contract has no bytecode) + continue; + } + } + + if let Some(bytecode_obj) = current.as_str() { + let bytecode_hex = bytecode_obj.strip_prefix("0x").unwrap_or(bytecode_obj); + let binary_content = hex::decode(bytecode_hex).map_err(|e| { + anyhow::anyhow!("Failed to decode hex for {contract_name}: {e}") + })?; + + let out_path = out_dir.join(format!("{}{}", contract_name, file_suffix)); + fs::write(&out_path, binary_content).with_context(|| { + format!("Failed to write {out_path:?} for {contract_name}") + })?; + } + } + } + } + } + Ok(()) +} + +/// Compile Solidity contracts using both solc and resolc. +fn compile_solidity_contracts( + contracts_dir: &Path, + out_dir: &Path, + entries: &[Entry], +) -> Result<()> { + let solidity_entries: Vec<_> = entries + .iter() + .filter(|entry| matches!(entry.contract_type, ContractType::Solidity)) + .collect(); + + if solidity_entries.is_empty() { + return Ok(()); + } + + // Compile with solc for EVM bytecode + let json = compile_with_standard_json("solc", contracts_dir, &solidity_entries)?; + extract_and_write_bytecode(&json, out_dir, ".sol.bin")?; + + // Compile with resolc for PVM bytecode + let json = compile_with_standard_json("resolc", contracts_dir, &solidity_entries)?; + extract_and_write_bytecode(&json, out_dir, ".resolc.polkavm")?; + + Ok(()) +} + +/// Write the compiled Rust contracts to the given output directory. fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec) -> Result<()> { for entry in entries { - post_process( - &build_dir - .join("target/riscv64emac-unknown-none-polkavm/release") - .join(entry.name()), - &out_dir.join(entry.out_filename()), - )?; + if matches!(entry.contract_type, ContractType::Rust) { + post_process( + &build_dir + .join("target/riscv64emac-unknown-none-polkavm/release") + .join(entry.name()), + &out_dir.join(entry.out_filename()), + )?; + } } Ok(()) @@ -211,7 +376,7 @@ fn create_out_dir() -> Result { let temp_dir: PathBuf = env::var("OUT_DIR").context("Failed to fetch `OUT_DIR` env variable")?.into(); - // this is set in case the user has overriden the target directory + // this is set in case the user has overridden the target directory let out_dir = if let Ok(path) = env::var("CARGO_TARGET_DIR") { let path = PathBuf::from(path); @@ -263,25 +428,46 @@ fn create_out_dir() -> Result { .context(format!("Failed to create output directory: {})", out_dir.display(),))?; } - // write the location of the out dir so it can be found later + Ok(out_dir) +} + +/// Generate the fixture_location.rs file with macros and sol! definitions. +fn generate_fixture_location(temp_dir: &Path, out_dir: &Path, entries: &[Entry]) -> Result<()> { let mut file = fs::File::create(temp_dir.join("fixture_location.rs")) .context("Failed to create fixture_location.rs")?; + write!( file, r#" #[allow(dead_code)] const FIXTURE_DIR: &str = "{0}"; + + #[macro_export] macro_rules! fixture {{ ($name: literal) => {{ include_bytes!(concat!("{0}", "/", $name, ".polkavm")) }}; }} + + #[macro_export] + macro_rules! fixture_resolc {{ + ($name: literal) => {{ + include_bytes!(concat!("{0}", "/", $name, ".resolc.polkavm")) + }}; + }} "#, out_dir.display() ) .context("Failed to write to fixture_location.rs")?; - Ok(out_dir) + // Generate sol! macros for Solidity contracts + for entry in entries.iter().filter(|e| matches!(e.contract_type, ContractType::Solidity)) { + let relative_path = format!("contracts/{}", entry.path().split('/').last().unwrap()); + writeln!(file, r#"alloy_core::sol!("{}");"#, relative_path) + .context("Failed to write sol! macro to fixture_location.rs")?; + } + + Ok(()) } pub fn main() -> Result<()> { @@ -305,12 +491,28 @@ pub fn main() -> Result<()> { let entries = collect_entries(&contracts_dir); if entries.is_empty() { - return Ok(()) + return Ok(()); } - create_cargo_toml(&fixtures_dir, entries.iter(), &build_dir)?; - invoke_build(&build_dir)?; - write_output(&build_dir, &out_dir, entries)?; + // Compile Rust contracts + let rust_entries: Vec<_> = entries + .iter() + .filter(|e| matches!(e.contract_type, ContractType::Rust)) + .collect(); + if !rust_entries.is_empty() { + create_cargo_toml(&fixtures_dir, rust_entries.into_iter(), &build_dir)?; + invoke_build(&build_dir)?; + write_output(&build_dir, &out_dir, entries.clone())?; + } + + // Compile Solidity contracts + compile_solidity_contracts(&contracts_dir, &out_dir, &entries)?; + + let temp_dir: PathBuf = + env::var("OUT_DIR").context("Failed to fetch `OUT_DIR` env variable")?.into(); + + // Generate fixture_location.rs with sol! macros + generate_fixture_location(&temp_dir, &out_dir, &entries)?; Ok(()) } diff --git a/substrate/frame/revive/fixtures/contracts/dummy.polkavm b/substrate/frame/revive/fixtures/contracts/dummy.polkavm deleted file mode 100644 index d970e700ce564485c496e1b5254d2f8d434db72d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1726 zcmb_bO>7fK7@hS`c5FhJHL+*ogs@NtIaR4#Rro-}lXX-%j$xTL9c_0~gYW&QEWDBQHPfe!ZAIoke zYB5jtolB2RWk)8*(`P0=$c~R^GhWR#yVujoJKNuu$(|jvOKr1{C3zqLqRM{dm~v0~ zMG3fiT}NDByYIStJvTjGujcLdzT&-9LMh)HrcVLNbz$D2uv*_;tFH~mB@sR32f%gx zV&Je8>@pz&t~(dh17Pb506TBL%ft2(?}qjb%5+*rv;-*?D{)%cEmmT*(koV?w6aUA z7_`zOR&-kF7AuHW!r}&`tV=A%DZ^qpMp;NKM=1-6WrMO#v8+?JQ!FFO0%8f$vL@!@ zw7f&i#b~)h%tdK=yO=X*xn0c3vfIQQqGi9h0%^%78gW`uMI%N_ZK4sSC9h~0wB!*D zotE69A5Jpdf-K0}ZNYg3Bfr5sj0z%}SqlgQ&sqP9Qe@-2qq zEEscwiJG=%stFSsNd#}M6TEu{5Zp`fE`oaq?j|@)a2LTk!I!9jvM3EoL?fMAVa zMDPxRI|$xRa67@<2=)`~BN!5_65K|xmtYUUZh~C|D@3(4-BK(KS{kZizp8MIxUTaq z$iu4wu3lAFFQ|iR$W%?3ME?EjRcfk=>GOLOQ=O3=OQLpty*h0|$ti~*l)~V4Q$@gC zo%Va5ZR+^#Q7h8)nE=UHM_XHGNLN@8DJ%pPCuk^Act+OQlpgr%(f=&nZ9?h#Q`s!9 zAKIKhvE*&tlU1s@TT+r=QO@VS2ZP6M-_5)nR8q%wz534Rn~H}k7Z->~EMOAPBQj93?BA=VRTdW>~PS*KCet6{_RJvO%)rs{8V z2Io0C$%9EQvumUBLT+?D^x9vWy=yh@KbX+I;lT;)#+&){A0KZ0MONsf6-rvNU~bgO zC#+Dy1mWjpX3p^oI&UC;5%Rj!)lyey`cqZd(&CmDv$UwC83S5kQ(3h;(GsWn-5kfc z9^+k69yVljy%o=jIx8TShb;G;a9$YYxjfIGc0IqZjKNW1t!7vr@yu&E`VHi7X!ZF4DKSPZs^`$l^xX=8&@xX*7qL WLw)^LYU3<@eV;@E$DPiA3;Yc>C+^?? diff --git a/substrate/frame/revive/fixtures/contracts/dummy.sol b/substrate/frame/revive/fixtures/contracts/dummy.sol deleted file mode 100644 index e64031b0e0210..0000000000000 --- a/substrate/frame/revive/fixtures/contracts/dummy.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.2 <0.9.0; - -contract Simple { - uint256 number; - - function store(uint256 num) public { - number = num; - } - - function retrieve() public view returns (uint256) { - return number; - } -} \ No newline at end of file diff --git a/substrate/frame/revive/fixtures/contracts/fake_erc20.sol b/substrate/frame/revive/fixtures/contracts/fake_erc20.sol deleted file mode 100644 index 1c6d0aca5c8c2..0000000000000 --- a/substrate/frame/revive/fixtures/contracts/fake_erc20.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -contract MyToken { - mapping(address account => uint256) private _balances; - - uint256 private _totalSupply; - - constructor(uint256 total) { - // We mint `total` tokens to the creator of this contract, as - // a sort of genesis. - _mint(msg.sender, total); - } - - function transfer(address to, uint256 value) public virtual returns (uint256) { - address owner = msg.sender; - _transfer(owner, to, value); - return 1243657816489523; - } - - function _transfer(address from, address to, uint256 value) internal { - _update(from, to, value); - } - - function _update(address from, address to, uint256 value) internal virtual { - if (from == address(0)) { - // Overflow check required: The rest of the code assumes that totalSupply never overflows - _totalSupply += value; - } else { - uint256 fromBalance = _balances[from]; - unchecked { - // Overflow not possible: value <= fromBalance <= totalSupply. - _balances[from] = fromBalance - value; - } - } - - if (to == address(0)) { - unchecked { - // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. - _totalSupply -= value; - } - } else { - unchecked { - // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. - _balances[to] += value; - } - } - } - - function _mint(address account, uint256 value) internal { - _update(address(0), account, value); - } -} - diff --git a/substrate/frame/revive/fixtures/contracts/erc20.polkavm b/substrate/frame/revive/fixtures/erc20/erc20.polkavm similarity index 100% rename from substrate/frame/revive/fixtures/contracts/erc20.polkavm rename to substrate/frame/revive/fixtures/erc20/erc20.polkavm diff --git a/substrate/frame/revive/fixtures/contracts/erc20.sol b/substrate/frame/revive/fixtures/erc20/erc20.sol similarity index 100% rename from substrate/frame/revive/fixtures/contracts/erc20.sol rename to substrate/frame/revive/fixtures/erc20/erc20.sol diff --git a/substrate/frame/revive/fixtures/contracts/expensive_erc20.polkavm b/substrate/frame/revive/fixtures/erc20/expensive_erc20.polkavm similarity index 100% rename from substrate/frame/revive/fixtures/contracts/expensive_erc20.polkavm rename to substrate/frame/revive/fixtures/erc20/expensive_erc20.polkavm diff --git a/substrate/frame/revive/fixtures/contracts/expensive_erc20.sol b/substrate/frame/revive/fixtures/erc20/expensive_erc20.sol similarity index 100% rename from substrate/frame/revive/fixtures/contracts/expensive_erc20.sol rename to substrate/frame/revive/fixtures/erc20/expensive_erc20.sol diff --git a/substrate/frame/revive/fixtures/contracts/fake_erc20.polkavm b/substrate/frame/revive/fixtures/erc20/fake_erc20.polkavm similarity index 100% rename from substrate/frame/revive/fixtures/contracts/fake_erc20.polkavm rename to substrate/frame/revive/fixtures/erc20/fake_erc20.polkavm diff --git a/substrate/frame/revive/fixtures/src/lib.rs b/substrate/frame/revive/fixtures/src/lib.rs index 8d6a8236cd742..022dcb9b43f09 100644 --- a/substrate/frame/revive/fixtures/src/lib.rs +++ b/substrate/frame/revive/fixtures/src/lib.rs @@ -22,16 +22,47 @@ extern crate alloc; // generated file that tells us where to find the fixtures include!(concat!(env!("OUT_DIR"), "/fixture_location.rs")); -/// Load a given polkavm module and returns a polkavm binary contents along with its hash. +/// Enum for different fixture types +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FixtureType { + /// Polkavm (compiled Rust contracts) + Rust, + /// Resolc (compiled Solidity contracts to Polkavm) + Resolc, + /// Solc (compiled Solidity contracts to EVM bytecode) + Solc, +} + #[cfg(feature = "std")] -pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H256)> { +impl FixtureType { + fn file_extension(&self) -> &'static str { + match self { + Self::Rust => ".polkavm", + Self::Resolc => ".resolc.polkavm", + Self::Solc => ".sol.bin", + } + } +} + +/// Load a fixture module with the specified type and return binary contents along with its hash. +#[cfg(feature = "std")] +pub fn compile_module_with_type( + fixture_name: &str, + fixture_type: FixtureType, +) -> anyhow::Result<(Vec, sp_core::H256)> { let out_dir: std::path::PathBuf = FIXTURE_DIR.into(); - let fixture_path = out_dir.join(format!("{fixture_name}.polkavm")); + let fixture_path = out_dir.join(format!("{fixture_name}{}", fixture_type.file_extension())); let binary = std::fs::read(fixture_path)?; let code_hash = sp_io::hashing::keccak_256(&binary); Ok((binary, sp_core::H256(code_hash))) } +/// Load a given polkavm module and returns a polkavm binary contents along with its hash. +#[cfg(feature = "std")] +pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H256)> { + compile_module_with_type(fixture_name, FixtureType::Rust) +} + /// Fixtures used in runtime benchmarks. /// /// We explicitly include those fixtures into the binary to make them diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 84819744b2ffb..8d7fd221ec6cc 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -27,6 +27,7 @@ use crate::{ self, run::builtin as run_builtin_precompile, BenchmarkSystem, BuiltinPrecompile, ISystem, }, storage::WriteOutcome, + vm::pvm, Pallet as Contracts, *, }; use alloc::{vec, vec::Vec}; @@ -79,7 +80,7 @@ macro_rules! build_runtime( let $contract = setup.contract(); let input = setup.data(); let (mut ext, _) = setup.ext(); - let mut $runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, input); + let mut $runtime = $crate::vm::pvm::Runtime::<_, [u8]>::new(&mut ext, input); }; ); @@ -654,7 +655,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![]); let result; #[block] @@ -793,7 +794,7 @@ mod benchmarks { let (mut ext, _) = setup.ext(); ext.override_export(crate::exec::ExportedFunction::Constructor); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, input); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, input); let result; #[block] @@ -833,7 +834,7 @@ mod benchmarks { fn seal_return_data_size() { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![]); let mut memory = memory!(vec![],); *runtime.ext().last_frame_output_mut() = ExecReturnValue { data: vec![42; 256], ..Default::default() }; @@ -849,7 +850,7 @@ mod benchmarks { fn seal_call_data_size() { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![42u8; 128 as usize]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![42u8; 128 as usize]); let mut memory = memory!(vec![0u8; 4],); let result; #[block] @@ -962,7 +963,7 @@ mod benchmarks { let (mut ext, _) = setup.ext(); ext.set_block_number(BlockNumberFor::::from(1u32)); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, input); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, input); let block_hash = H256::from([1; 32]); frame_system::BlockHash::::insert( @@ -1013,7 +1014,7 @@ mod benchmarks { fn seal_copy_to_contract(n: Linear<0, { limits::code::BLOB_BYTES - 4 }>) { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![]); let mut memory = memory!(n.encode(), vec![0u8; n as usize],); let result; #[block] @@ -1036,7 +1037,7 @@ mod benchmarks { fn seal_call_data_load() { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![42u8; 32]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![42u8; 32]); let mut memory = memory!(vec![0u8; 32],); let result; #[block] @@ -1051,7 +1052,7 @@ mod benchmarks { fn seal_call_data_copy(n: Linear<0, { limits::code::BLOB_BYTES }>) { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![42u8; n as usize]); + let mut runtime = pvm::Runtime::new(&mut ext, vec![42u8; n as usize]); let mut memory = memory!(vec![0u8; n as usize],); let result; #[block] @@ -1072,7 +1073,10 @@ mod benchmarks { result = runtime.bench_seal_return(memory.as_mut_slice(), 0, 0, n); } - assert!(matches!(result, Err(crate::vm::TrapReason::Return(crate::vm::ReturnData { .. })))); + assert!(matches!( + result, + Err(crate::vm::pvm::TrapReason::Return(crate::vm::pvm::ReturnData { .. })) + )); } #[benchmark(pov_mode = Measured)] @@ -1087,7 +1091,7 @@ mod benchmarks { result = runtime.bench_terminate(memory.as_mut_slice(), 0); } - assert!(matches!(result, Err(crate::vm::TrapReason::Termination))); + assert!(matches!(result, Err(crate::vm::pvm::TrapReason::Termination))); Ok(()) } @@ -1391,7 +1395,7 @@ mod benchmarks { let value = Some(vec![42u8; max_value_len as _]); let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX; let result; #[block] @@ -1414,7 +1418,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_transient_storage_size(limits::TRANSIENT_STORAGE_BYTES); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX; let result; #[block] @@ -1436,7 +1440,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX; runtime .ext() @@ -1462,7 +1466,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_transient_storage_size(limits::TRANSIENT_STORAGE_BYTES); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX; runtime .ext() @@ -1489,7 +1493,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_transient_storage_size(limits::TRANSIENT_STORAGE_BYTES); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX; runtime.ext().transient_storage().start_transaction(); runtime @@ -1702,7 +1706,7 @@ mod benchmarks { setup.set_balance(value + 1u32.into() + Pallet::::min_balance()); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let mut memory = memory!(callee_bytes, deposit_bytes, value_bytes,); let result; @@ -1759,7 +1763,7 @@ mod benchmarks { setup.set_storage_deposit_limit(deposit); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let mut memory = memory!(callee_bytes, deposit_bytes, value_bytes, input_bytes,); let mut do_benchmark = || { @@ -1805,7 +1809,7 @@ mod benchmarks { setup.set_origin(Origin::from_account_id(setup.contract().account_id.clone())); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let mut memory = memory!(address_bytes, deposit_bytes,); let result; @@ -1856,7 +1860,7 @@ mod benchmarks { let account_id = &setup.contract().account_id.clone(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let mut runtime = pvm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let input = vec![42u8; i as _]; let input_len = hash_bytes.len() as u32 + input.len() as u32; @@ -2076,7 +2080,9 @@ mod benchmarks { fn bn128_add() { use hex_literal::hex; let input = hex!("089142debb13c461f61523586a60732d8b69c5b38a3380a74da7b2961d867dbf2d5fc7bbc013c16d7945f190b232eacc25da675c0eb093fe6b9f1b4b4e107b3625f8c89ea3437f44f8fc8b6bfbb6312074dc6f983809a5e809ff4e1d076dd5850b38c7ced6e4daef9c4347f370d6d8b58f4b1d8dc61a3c59d651a0644a2a27cf").to_vec(); - let expected = hex!("0a6678fd675aa4d8f0d03a1feb921a27f38ebdcb860cc083653519655acd6d79172fd5b3b2bfdd44e43bcec3eace9347608f9f0a16f1e184cb3f52e6f259cbeb"); + let expected = hex!( + "0a6678fd675aa4d8f0d03a1feb921a27f38ebdcb860cc083653519655acd6d79172fd5b3b2bfdd44e43bcec3eace9347608f9f0a16f1e184cb3f52e6f259cbeb" + ); let mut call_setup = CallSetup::::default(); let (mut ext, _) = call_setup.ext(); @@ -2094,7 +2100,9 @@ mod benchmarks { fn bn128_mul() { use hex_literal::hex; let input = hex!("089142debb13c461f61523586a60732d8b69c5b38a3380a74da7b2961d867dbf2d5fc7bbc013c16d7945f190b232eacc25da675c0eb093fe6b9f1b4b4e107b36ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").to_vec(); - let expected = hex!("0bf982b98a2757878c051bfe7eee228b12bc69274b918f08d9fcb21e9184ddc10b17c77cbf3c19d5d27e18cbd4a8c336afb488d0e92c18d56e64dd4ea5c437e6"); + let expected = hex!( + "0bf982b98a2757878c051bfe7eee228b12bc69274b918f08d9fcb21e9184ddc10b17c77cbf3c19d5d27e18cbd4a8c336afb488d0e92c18d56e64dd4ea5c437e6" + ); let mut call_setup = CallSetup::::default(); let (mut ext, _) = call_setup.ext(); @@ -2161,7 +2169,9 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn blake2f(n: Linear<0, 1200>) { use hex_literal::hex; - let input = hex!("48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); + let input = hex!( + "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001" + ); let input = n.to_be_bytes().to_vec().into_iter().chain(input.to_vec()).collect::>(); let mut call_setup = CallSetup::::default(); let (mut ext, _) = call_setup.ext(); diff --git a/substrate/frame/revive/src/call_builder.rs b/substrate/frame/revive/src/call_builder.rs index 683cd5d5db803..1213dc874d4e5 100644 --- a/substrate/frame/revive/src/call_builder.rs +++ b/substrate/frame/revive/src/call_builder.rs @@ -31,7 +31,7 @@ use crate::{ limits, storage::meter::Meter, transient_storage::MeterEntry, - vm::{PreparedCall, Runtime}, + vm::pvm::{PreparedCall, Runtime}, AccountInfo, BalanceOf, BalanceWithDust, BumpNonce, Code, CodeInfoOf, Config, ContractBlob, ContractInfo, DepositLimit, Error, GasMeter, MomentOf, Origin, Pallet as Contracts, PristineCode, Weight, diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index ec277d562f825..4cd9c6d93dca0 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -61,6 +61,9 @@ use sp_runtime::{ #[cfg(test)] mod tests; +#[cfg(test)] +pub mod mock_ext; + pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; pub type ExecResult = Result; @@ -474,6 +477,11 @@ pub trait Executable: Sized { /// The code hash of the executable. fn code_hash(&self) -> &H256; + + /// Returns true if the executable is a PVM blob. + fn is_pvm(&self) -> bool { + self.code().starts_with(&polkavm_common::program::BLOB_MAGIC) + } } /// The complete call stack of a contract execution. @@ -567,6 +575,13 @@ impl, Env> ExecutableOrPrecompile { } } + fn is_pvm(&self) -> bool { + match self { + Self::Executable(e) => e.is_pvm(), + _ => false, + } + } + fn as_precompile(&self) -> Option<&PrecompileInstance> { if let Self::Precompile { instance, .. } = self { Some(instance) @@ -1087,6 +1102,7 @@ where ) -> Result<(), ExecError> { let frame = self.top_frame(); let entry_point = frame.entry_point; + let is_pvm = executable.is_pvm(); if_tracing(|tracer| { tracer.enter_child_span( @@ -1157,12 +1173,14 @@ where >::inc_account_nonce(caller.account_id()?); } // The incremented refcount should be visible to the constructor. - >::increment_refcount( - *executable - .as_executable() - .expect("Precompiles cannot be instantiated; qed") - .code_hash(), - )?; + if is_pvm { + >::increment_refcount( + *executable + .as_executable() + .expect("Precompiles cannot be instantiated; qed") + .code_hash(), + )?; + } } // Every non delegate call or instantiate also optionally transfers the balance. @@ -1229,7 +1247,8 @@ where // The deposit we charge for a contract depends on the size of the immutable data. // Hence we need to delay charging the base deposit after execution. if entry_point == ExportedFunction::Constructor { - let deposit = frame.contract_info().update_base_deposit(code_deposit); + let contract_info = frame.contract_info(); + let deposit = contract_info.update_base_deposit(code_deposit); frame .nested_storage .charge_deposit(frame.account_id.clone(), StorageDeposit::Charge(deposit)); @@ -2075,6 +2094,8 @@ mod sealing { use super::*; pub trait Sealed {} - impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {} + + #[cfg(test)] + impl sealing::Sealed for mock_ext::MockExt {} } diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs new file mode 100644 index 0000000000000..63b10c60eedda --- /dev/null +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -0,0 +1,259 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +use crate::{ + exec::{AccountIdOf, ExecError, Ext, Key, Origin, PrecompileExt, PrecompileWithInfoExt}, + gas::GasMeter, + precompiles::Diff, + storage::{ContractInfo, WriteOutcome}, + transient_storage::TransientStorage, + Config, ExecReturnValue, ImmutableData, +}; +use alloc::vec::Vec; +use core::marker::PhantomData; +use frame_support::{dispatch::DispatchResult, weights::Weight}; +use sp_core::{H160, H256, U256}; +use sp_runtime::DispatchError; + +/// Mock implementation of the Ext trait that panics for all methods +pub struct MockExt { + gas_meter: GasMeter, + _phantom: PhantomData, +} + +impl PrecompileExt for MockExt { + type T = T; + + fn call( + &mut self, + _gas_limit: Weight, + _deposit_limit: U256, + _to: &H160, + _value: U256, + _input_data: Vec, + _allows_reentry: bool, + _read_only: bool, + ) -> Result<(), ExecError> { + panic!("MockExt::call") + } + + fn get_transient_storage(&self, _key: &Key) -> Option> { + panic!("MockExt::get_transient_storage") + } + + fn get_transient_storage_size(&self, _key: &Key) -> Option { + panic!("MockExt::get_transient_storage_size") + } + + fn set_transient_storage( + &mut self, + _key: &Key, + _value: Option>, + _take_old: bool, + ) -> Result { + panic!("MockExt::set_transient_storage") + } + + fn caller(&self) -> Origin { + panic!("MockExt::caller") + } + + fn origin(&self) -> &Origin { + panic!("MockExt::origin") + } + + fn code_hash(&self, _address: &H160) -> H256 { + panic!("MockExt::code_hash") + } + + fn code_size(&self, _address: &H160) -> u64 { + panic!("MockExt::code_size") + } + + fn caller_is_origin(&self) -> bool { + panic!("MockExt::caller_is_origin") + } + + fn caller_is_root(&self) -> bool { + panic!("MockExt::caller_is_root") + } + + fn account_id(&self) -> &AccountIdOf { + panic!("MockExt::account_id") + } + + fn balance(&self) -> U256 { + panic!("MockExt::balance") + } + + fn balance_of(&self, _address: &H160) -> U256 { + panic!("MockExt::balance_of") + } + + fn value_transferred(&self) -> U256 { + panic!("MockExt::value_transferred") + } + + fn now(&self) -> U256 { + panic!("MockExt::now") + } + + fn minimum_balance(&self) -> U256 { + panic!("MockExt::minimum_balance") + } + + fn deposit_event(&mut self, _topics: Vec, _data: Vec) { + panic!("MockExt::deposit_event") + } + + fn block_number(&self) -> U256 { + panic!("MockExt::block_number") + } + + fn block_hash(&self, _block_number: U256) -> Option { + panic!("MockExt::block_hash") + } + + fn block_author(&self) -> Option { + panic!("MockExt::block_author") + } + + fn max_value_size(&self) -> u32 { + panic!("MockExt::max_value_size") + } + + fn get_weight_price(&self, _weight: Weight) -> U256 { + panic!("MockExt::get_weight_price") + } + + fn gas_meter(&self) -> &GasMeter { + &self.gas_meter + } + + fn gas_meter_mut(&mut self) -> &mut GasMeter { + &mut self.gas_meter + } + + fn ecdsa_recover( + &self, + _signature: &[u8; 65], + _message_hash: &[u8; 32], + ) -> Result<[u8; 33], ()> { + panic!("MockExt::ecdsa_recover") + } + + fn sr25519_verify(&self, _signature: &[u8; 64], _message: &[u8], _pub_key: &[u8; 32]) -> bool { + panic!("MockExt::sr25519_verify") + } + + fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> { + panic!("MockExt::ecdsa_to_eth_address") + } + + #[cfg(any(test, feature = "runtime-benchmarks"))] + fn contract_info(&mut self) -> &mut ContractInfo { + panic!("MockExt::contract_info") + } + + #[cfg(any(feature = "runtime-benchmarks", test))] + fn transient_storage(&mut self) -> &mut TransientStorage { + panic!("MockExt::transient_storage") + } + + fn is_read_only(&self) -> bool { + panic!("MockExt::is_read_only") + } + + fn last_frame_output(&self) -> &ExecReturnValue { + panic!("MockExt::last_frame_output") + } + + fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue { + panic!("MockExt::last_frame_output_mut") + } +} + +impl PrecompileWithInfoExt for MockExt { + fn get_storage(&mut self, _key: &Key) -> Option> { + panic!("MockExt::get_storage") + } + + fn get_storage_size(&mut self, _key: &Key) -> Option { + panic!("MockExt::get_storage_size") + } + + fn set_storage( + &mut self, + _key: &Key, + _value: Option>, + _take_old: bool, + ) -> Result { + panic!("MockExt::set_storage") + } + + fn charge_storage(&mut self, _diff: &Diff) {} + + fn instantiate( + &mut self, + _gas_limit: Weight, + _deposit_limit: U256, + _code: H256, + _value: U256, + _input_data: Vec, + _salt: Option<&[u8; 32]>, + ) -> Result { + panic!("MockExt::instantiate") + } +} + +impl Ext for MockExt { + fn delegate_call( + &mut self, + _gas_limit: Weight, + _deposit_limit: U256, + _address: H160, + _input_data: Vec, + ) -> Result<(), ExecError> { + panic!("MockExt::delegate_call") + } + + fn terminate(&mut self, _beneficiary: &H160) -> DispatchResult { + panic!("MockExt::terminate") + } + + fn own_code_hash(&mut self) -> &H256 { + panic!("MockExt::own_code_hash") + } + + fn set_code_hash(&mut self, _hash: H256) -> DispatchResult { + panic!("MockExt::set_code_hash") + } + + fn immutable_data_len(&mut self) -> u32 { + panic!("MockExt::immutable_data_len") + } + + fn get_immutable_data(&mut self) -> Result { + panic!("MockExt::get_immutable_data") + } + + fn set_immutable_data(&mut self, _data: ImmutableData) -> Result<(), DispatchError> { + panic!("MockExt::set_immutable_data") + } +} diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 381abc7c26117..9b1995e2db7ef 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -176,6 +176,10 @@ impl Executable for MockExecutable { self.code_hash.as_ref() } + fn is_pvm(&self) -> bool { + true + } + fn code_hash(&self) -> &H256 { &self.code_hash } diff --git a/substrate/frame/revive/src/impl_fungibles.rs b/substrate/frame/revive/src/impl_fungibles.rs index 55c42a5091098..404690c6765b4 100644 --- a/substrate/frame/revive/src/impl_fungibles.rs +++ b/substrate/frame/revive/src/impl_fungibles.rs @@ -302,13 +302,14 @@ mod tests { AccountInfoOf, Code, }; use frame_support::assert_ok; + const ERC20_PVM_CODE: &[u8] = include_bytes!("../fixtures/erc20/erc20.polkavm"); #[test] fn call_erc20_contract() { ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let _ = <::Currency as fungible::Mutate<_>>::set_balance(&ALICE, 1_000_000); - let code = include_bytes!("../fixtures/contracts/erc20.polkavm").to_vec(); + let code = ERC20_PVM_CODE.to_vec(); let amount = EU256::from(1000); let constructor_data = sol_data::Uint::<256>::abi_encode(&amount); let Contract { addr, .. } = BareInstantiateBuilder::::bare_instantiate( @@ -333,7 +334,7 @@ mod tests { ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let _ = <::Currency as fungible::Mutate<_>>::set_balance(&ALICE, 1_000_000); - let code = include_bytes!("../fixtures/contracts/erc20.polkavm").to_vec(); + let code = ERC20_PVM_CODE.to_vec(); let amount = 1000; let constructor_data = sol_data::Uint::<256>::abi_encode(&EU256::from(amount)); let Contract { addr, .. } = BareInstantiateBuilder::::bare_instantiate( @@ -353,7 +354,7 @@ mod tests { ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let _ = <::Currency as fungible::Mutate<_>>::set_balance(&ALICE, 1_000_000); - let code = include_bytes!("../fixtures/contracts/erc20.polkavm").to_vec(); + let code = ERC20_PVM_CODE.to_vec(); let amount = 1000; let constructor_data = sol_data::Uint::<256>::abi_encode(&EU256::from(amount)); let Contract { addr, .. } = BareInstantiateBuilder::::bare_instantiate( @@ -371,7 +372,7 @@ mod tests { ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let _ = <::Currency as fungible::Mutate<_>>::set_balance(&ALICE, 1_000_000); - let code = include_bytes!("../fixtures/contracts/erc20.polkavm").to_vec(); + let code = ERC20_PVM_CODE.to_vec(); let amount = 1000; let constructor_data = sol_data::Uint::<256>::abi_encode(&(EU256::from(amount * 2))); let Contract { addr, .. } = BareInstantiateBuilder::::bare_instantiate( @@ -407,7 +408,7 @@ mod tests { &checking_account, 1_000_000, ); - let code = include_bytes!("../fixtures/contracts/erc20.polkavm").to_vec(); + let code = ERC20_PVM_CODE.to_vec(); let amount = 1000; let constructor_data = sol_data::Uint::<256>::abi_encode(&EU256::from(amount)); // We're instantiating the contract with the `CheckingAccount` so it has `amount` in it. diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 8b2d7f76e716a..11c69bfdfe9e3 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -102,7 +102,7 @@ pub use sp_runtime; pub use weights::WeightInfo; #[cfg(doc)] -pub use crate::vm::SyscallDoc; +pub use crate::vm::pvm::SyscallDoc; pub type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; @@ -1135,9 +1135,9 @@ where if_tracing(|t| t.instantiate_code(&code, salt.as_ref())); let (executable, upload_deposit) = match code { - Code::Upload(code) => { + Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => { let upload_account = T::UploadOrigin::ensure_origin(origin)?; - let (executable, upload_deposit) = Self::try_upload_code( + let (executable, upload_deposit) = Self::try_upload_pvm_code( upload_account, code, storage_deposit_limit, @@ -1146,6 +1146,7 @@ where storage_deposit_limit.saturating_reduce(upload_deposit); (executable, upload_deposit) }, + Code::Upload(_code) => return Err(>::CodeRejected.into()), Code::Existing(code_hash) => (ContractBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()), }; @@ -1245,10 +1246,10 @@ where err == Error::::StorageDepositLimitExhausted.into() { let balance = Self::evm_balance(&from); - return Err(EthTransactError::Message( - format!("insufficient funds for gas * price + value: address {from:?} have {balance} (supplied gas {})", - tx.gas.unwrap_or_default())) - ); + return Err(EthTransactError::Message(format!( + "insufficient funds for gas * price + value: address {from:?} have {balance} (supplied gas {})", + tx.gas.unwrap_or_default() + ))); } return Err(EthTransactError::Message(format!( @@ -1331,16 +1332,20 @@ where // A contract deployment None => { // Extract code and data from the input. - let (code, data) = match polkavm::ProgramBlob::blob_length(&input) { - Some(blob_len) => blob_len - .try_into() - .ok() - .and_then(|blob_len| (input.split_at_checked(blob_len))) - .unwrap_or_else(|| (&input[..], &[][..])), - _ => { - log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length"); - (&input[..], &[][..]) - }, + let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) { + match polkavm::ProgramBlob::blob_length(&input) { + Some(blob_len) => blob_len + .try_into() + .ok() + .and_then(|blob_len| (input.split_at_checked(blob_len))) + .unwrap_or_else(|| (&input[..], &[][..])), + _ => { + log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length"); + (&input[..], &[][..]) + }, + } + } else { + return Err(EthTransactError::Message("Invalid transaction".into())); }; // Dry run the call. @@ -1501,7 +1506,8 @@ where storage_deposit_limit: BalanceOf, ) -> CodeUploadResult> { let origin = T::UploadOrigin::ensure_origin(origin)?; - let (module, deposit) = Self::try_upload_code(origin, code, storage_deposit_limit, false)?; + let (module, deposit) = + Self::try_upload_pvm_code(origin, code, storage_deposit_limit, false)?; Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit }) } @@ -1528,13 +1534,13 @@ where } /// Uploads new code and returns the Vm binary contract blob and deposit amount collected. - fn try_upload_code( + fn try_upload_pvm_code( origin: T::AccountId, code: Vec, storage_deposit_limit: BalanceOf, skip_transfer: bool, ) -> Result<(ContractBlob, BalanceOf), DispatchError> { - let mut module = ContractBlob::from_code(code, origin)?; + let mut module = ContractBlob::from_pvm_code(code, origin)?; let deposit = module.store_code(skip_transfer)?; ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); Ok((module, deposit)) diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 0cee2e3d9499a..9b3a3c10a932c 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -17,49 +17,24 @@ mod pallet_dummy; mod precompiles; +mod pvm; -use self::test_utils::{ensure_stored, expected_deposit}; use crate::{ - self as pallet_revive, - address::{create1, create2, AddressMapper}, - evm::{runtime::GAS_PRICE, CallTrace, CallTracer, CallType, GenericTransaction}, - exec::Key, - limits, - storage::DeletionQueueManager, - test_utils::{builder::Contract, *}, - tests::test_utils::{get_contract, get_contract_checked}, - tracing::trace, - weights::WeightInfo, - AccountId32Mapper, AccountInfo, AccountInfoOf, BalanceOf, BalanceWithDust, BumpNonce, Code, - CodeInfoOf, Config, ContractInfo, DeletionQueueCounter, DepositLimit, Error, EthTransactError, - HoldReason, Origin, Pallet, PristineCode, StorageDeposit, H160, + self as pallet_revive, test_utils::*, AccountId32Mapper, BalanceOf, BalanceWithDust, + CodeInfoOf, Config, Origin, Pallet, }; -use assert_matches::assert_matches; -use codec::Encode; use frame_support::{ - assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, derive_impl, + assert_ok, derive_impl, pallet_prelude::EnsureOrigin, parameter_types, - storage::child, - traits::{ - fungible::{BalancedHold, Inspect, Mutate, MutateHold}, - tokens::Preservation, - ConstU32, ConstU64, FindAuthor, OnIdle, OnInitialize, StorageVersion, - }, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, FixedFee, IdentityFee, Weight, WeightMeter}, + traits::{ConstU32, ConstU64, FindAuthor, StorageVersion}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, FixedFee, IdentityFee, Weight}, }; -use frame_system::{EventRecord, Phase}; -use pallet_revive_fixtures::compile_module; -use pallet_revive_uapi::{ReturnErrorCode as RuntimeReturnCode, ReturnFlags}; use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier}; -use pretty_assertions::{assert_eq, assert_ne}; -use sp_core::{Get, U256}; -use sp_io::hashing::blake2_256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ - testing::H256, - traits::{BlakeTwo256, Convert, IdentityLookup, One, Zero}, - AccountId32, BuildStorage, DispatchError, Perbill, TokenError, + traits::{BlakeTwo256, Convert, IdentityLookup, One}, + AccountId32, BuildStorage, Perbill, }; type Block = frame_system::mocking::MockBlock; @@ -78,12 +53,14 @@ frame_support::construct_runtime!( } ); +#[macro_export] macro_rules! assert_return_code { ( $x:expr , $y:expr $(,)? ) => {{ assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); }}; } +#[macro_export] macro_rules! assert_refcount { ( $code_hash:expr , $should:expr $(,)? ) => {{ let is = crate::CodeInfoOf::::get($code_hash).map(|m| m.refcount()).unwrap(); @@ -194,7 +171,7 @@ pub mod test_utils { } } -mod builder { +pub(crate) mod builder { use super::Test; use crate::{ test_utils::{builder::*, ALICE}, @@ -457,4844 +434,3 @@ impl Default for Origin { Self::Signed(ALICE) } } - -#[test] -fn transfer_with_dust_works() { - struct TestCase { - description: &'static str, - from_balance: BalanceWithDust, - to_balance: BalanceWithDust, - amount: BalanceWithDust, - expected_from_balance: BalanceWithDust, - expected_to_balance: BalanceWithDust, - total_issuance_diff: i64, - } - - let plank: u32 = ::NativeToEthRatio::get(); - - let test_cases = vec![ - TestCase { - description: "without dust", - from_balance: BalanceWithDust::new_unchecked::(100, 0), - to_balance: BalanceWithDust::new_unchecked::(0, 0), - amount: BalanceWithDust::new_unchecked::(1, 0), - expected_from_balance: BalanceWithDust::new_unchecked::(99, 0), - expected_to_balance: BalanceWithDust::new_unchecked::(1, 0), - total_issuance_diff: 0, - }, - TestCase { - description: "with dust", - from_balance: BalanceWithDust::new_unchecked::(100, 0), - to_balance: BalanceWithDust::new_unchecked::(0, 0), - amount: BalanceWithDust::new_unchecked::(1, 10), - expected_from_balance: BalanceWithDust::new_unchecked::(98, plank - 10), - expected_to_balance: BalanceWithDust::new_unchecked::(1, 10), - total_issuance_diff: 1, - }, - TestCase { - description: "just dust", - from_balance: BalanceWithDust::new_unchecked::(100, 0), - to_balance: BalanceWithDust::new_unchecked::(0, 0), - amount: BalanceWithDust::new_unchecked::(0, 10), - expected_from_balance: BalanceWithDust::new_unchecked::(99, plank - 10), - expected_to_balance: BalanceWithDust::new_unchecked::(0, 10), - total_issuance_diff: 1, - }, - TestCase { - description: "with existing dust", - from_balance: BalanceWithDust::new_unchecked::(100, 5), - to_balance: BalanceWithDust::new_unchecked::(0, plank - 5), - amount: BalanceWithDust::new_unchecked::(1, 10), - expected_from_balance: BalanceWithDust::new_unchecked::(98, plank - 5), - expected_to_balance: BalanceWithDust::new_unchecked::(2, 5), - total_issuance_diff: 0, - }, - TestCase { - description: "with enough existing dust", - from_balance: BalanceWithDust::new_unchecked::(100, 10), - to_balance: BalanceWithDust::new_unchecked::(0, plank - 10), - amount: BalanceWithDust::new_unchecked::(1, 10), - expected_from_balance: BalanceWithDust::new_unchecked::(99, 0), - expected_to_balance: BalanceWithDust::new_unchecked::(2, 0), - total_issuance_diff: -1, - }, - TestCase { - description: "receiver dust less than 1 plank", - from_balance: BalanceWithDust::new_unchecked::(100, plank / 10), - to_balance: BalanceWithDust::new_unchecked::(0, plank / 2), - amount: BalanceWithDust::new_unchecked::(1, plank / 10 * 3), - expected_from_balance: BalanceWithDust::new_unchecked::(98, plank / 10 * 8), - expected_to_balance: BalanceWithDust::new_unchecked::(1, plank / 10 * 8), - total_issuance_diff: 1, - }, - ]; - - for TestCase { - description, - from_balance, - to_balance, - amount, - expected_from_balance, - expected_to_balance, - total_issuance_diff, - } in test_cases.into_iter() - { - ExtBuilder::default().build().execute_with(|| { - test_utils::set_balance_with_dust(&ALICE_ADDR, from_balance); - test_utils::set_balance_with_dust(&BOB_ADDR, to_balance); - - let total_issuance = ::Currency::total_issuance(); - let evm_value = Pallet::::convert_native_to_evm(amount); - - let (value, dust) = amount.deconstruct(); - assert_eq!(Pallet::::has_dust(evm_value), !dust.is_zero()); - assert_eq!(Pallet::::has_balance(evm_value), !value.is_zero()); - - let result = - builder::bare_call(BOB_ADDR).evm_value(evm_value).build_and_unwrap_result(); - assert_eq!(result, Default::default(), "{description} tx failed"); - - assert_eq!( - Pallet::::evm_balance(&ALICE_ADDR), - Pallet::::convert_native_to_evm(expected_from_balance), - "{description}: invalid from balance" - ); - - assert_eq!( - Pallet::::evm_balance(&BOB_ADDR), - Pallet::::convert_native_to_evm(expected_to_balance), - "{description}: invalid to balance" - ); - - assert_eq!( - total_issuance as i64 - total_issuance_diff, - ::Currency::total_issuance() as i64, - "{description}: total issuance should match" - ); - }); - } -} - -#[test] -fn eth_call_transfer_with_dust_works() { - let (binary, _) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - let balance = - Pallet::::convert_native_to_evm(BalanceWithDust::new_unchecked::(100, 10)); - assert_ok!(builder::eth_call(addr).value(balance).build()); - - assert_eq!(Pallet::::evm_balance(&addr), balance); - }); -} - -#[test] -fn contract_call_transfer_with_dust_works() { - let (binary_caller, _code_hash_caller) = compile_module("call_with_value").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)) - .native_value(200) - .build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - let balance = - Pallet::::convert_native_to_evm(BalanceWithDust::new_unchecked::(100, 10)); - assert_ok!(builder::call(addr_caller).data((balance, addr_callee).encode()).build()); - - assert_eq!(Pallet::::evm_balance(&addr_callee), balance); - }); -} - -#[test] -fn deposit_limit_enforced_on_plain_transfer() { - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 1_000_000); - - // sending balance to a new account should fail when the limit is lower than the ed - let result = builder::bare_call(CHARLIE_ADDR) - .native_value(1) - .storage_deposit_limit(190.into()) - .build(); - assert_err!(result.result, >::StorageDepositLimitExhausted); - assert_eq!(result.storage_deposit, StorageDeposit::Charge(0)); - assert_eq!(test_utils::get_balance(&CHARLIE), 0); - - // works when the account is prefunded - let result = builder::bare_call(BOB_ADDR) - .native_value(1) - .storage_deposit_limit(0.into()) - .build(); - assert_ok!(result.result); - assert_eq!(result.storage_deposit, StorageDeposit::Charge(0)); - assert_eq!(test_utils::get_balance(&BOB), 1_000_001); - - // also works allowing enough deposit - let result = builder::bare_call(CHARLIE_ADDR) - .native_value(1) - .storage_deposit_limit(200.into()) - .build(); - assert_ok!(result.result); - assert_eq!(result.storage_deposit, StorageDeposit::Charge(200)); - assert_eq!(test_utils::get_balance(&CHARLIE), 201); - }); -} - -#[test] -fn instantiate_and_call_and_deposit_event() { - let (binary, code_hash) = compile_module("event_and_return_on_deploy").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let value = 100; - - // We determine the storage deposit limit after uploading because it depends on ALICEs - // free balance which is changed by uploading a module. - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - binary, - deposit_limit::(), - )); - - // Drop previous events - initialize_block(2); - - // Check at the end to get hash on error easily - let Contract { addr, account_id } = builder::bare_instantiate(Code::Existing(code_hash)) - .native_value(value) - .build_and_unwrap_contract(); - assert!(AccountInfoOf::::contains_key(&addr)); - - let hold_balance = test_utils::contract_base_deposit(&addr); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: value, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { - contract: addr, - data: vec![1, 2, 3, 4], - topics: vec![H256::repeat_byte(42)], - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: account_id.clone(), - transferred: hold_balance, - }), - topics: vec![], - }, - ] - ); - }); -} - -#[test] -fn create1_address_from_extrinsic() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - binary.clone(), - deposit_limit::(), - )); - - assert_eq!(System::account_nonce(&ALICE), 0); - System::inc_account_nonce(&ALICE); - - for nonce in 1..3 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .salt(None) - .build_and_unwrap_contract(); - assert!(AccountInfoOf::::contains_key(&addr)); - assert_eq!( - addr, - create1(&::AddressMapper::to_address(&ALICE), nonce - 1) - ); - } - assert_eq!(System::account_nonce(&ALICE), 3); - - for nonce in 3..6 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) - .salt(None) - .build_and_unwrap_contract(); - assert!(AccountInfoOf::::contains_key(&addr)); - assert_eq!( - addr, - create1(&::AddressMapper::to_address(&ALICE), nonce - 1) - ); - } - assert_eq!(System::account_nonce(&ALICE), 6); - }); -} - -#[test] -fn deposit_event_max_value_limit() { - let (binary, _code_hash) = compile_module("event_size").unwrap(); - - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(30_000) - .build_and_unwrap_contract(); - - // Call contract with allowed storage value. - assert_ok!(builder::call(addr) - .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer, - .data(limits::PAYLOAD_BYTES.encode()) - .build()); - - // Call contract with too large a storage value. - assert_err_ignore_postinfo!( - builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), - Error::::ValueTooLarge, - ); - }); -} - -// Fail out of fuel (ref_time weight) in the engine. -#[test] -fn run_out_of_fuel_engine() { - let (binary, _code_hash) = compile_module("run_out_of_gas").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(100 * min_balance) - .build_and_unwrap_contract(); - - // Call the contract with a fixed gas limit. It must run out of gas because it just - // loops forever. - assert_err_ignore_postinfo!( - builder::call(addr) - .gas_limit(Weight::from_parts(10_000_000_000, u64::MAX)) - .build(), - Error::::OutOfGas, - ); - }); -} - -// Fail out of fuel (ref_time weight) in the host. -#[test] -fn run_out_of_fuel_host() { - use crate::precompiles::Precompile; - use alloy_core::sol_types::SolInterface; - use precompiles::{INoInfo, NoInfo}; - - let precompile_addr = H160(NoInfo::::MATCHER.base_address()); - let input = INoInfo::INoInfoCalls::consumeMaxGas(INoInfo::consumeMaxGasCall {}).abi_encode(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let result = builder::bare_call(precompile_addr).data(input).build().result; - assert_err!(result, >::OutOfGas); - }); -} - -#[test] -fn gas_syncs_work() { - let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let contract = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let result = builder::bare_call(contract.addr).data(0u32.encode()).build(); - assert_ok!(result.result); - let engine_consumed_noop = result.gas_consumed.ref_time(); - - let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); - assert_ok!(result.result); - let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); - let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; - - let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); - assert_ok!(result.result); - let gas_consumed_twice = result.gas_consumed.ref_time(); - let host_consumed_twice = host_consumed_once * 2; - let engine_consumed_twice = gas_consumed_twice - host_consumed_twice - engine_consumed_noop; - - // Second contract just repeats first contract's instructions twice. - // If runtime syncs gas with the engine properly, this should pass. - assert_eq!(engine_consumed_twice, engine_consumed_once * 2); - }); -} - -/// Check that contracts with the same account id have different trie ids. -/// Check the `Nonce` storage item for more information. -#[test] -fn instantiate_unique_trie_id() { - let (binary, code_hash) = compile_module("self_destruct").unwrap(); - - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_limit::()) - .unwrap(); - - // Instantiate the contract and store its trie id for later comparison. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_contract(); - let trie_id = get_contract(&addr).trie_id; - - // Try to instantiate it again without termination should yield an error. - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).build(), - >::DuplicateContract, - ); - - // Terminate the contract. - assert_ok!(builder::call(addr).build()); - - // Re-Instantiate after termination. - assert_ok!(builder::instantiate(code_hash).build()); - - // Trie ids shouldn't match or we might have a collision - assert_ne!(trie_id, get_contract(&addr).trie_id); - }); -} - -#[test] -fn storage_work() { - let (code, _code_hash) = compile_module("storage").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - builder::bare_call(addr).build_and_unwrap_result(); - }); -} - -#[test] -fn storage_max_value_limit() { - let (binary, _code_hash) = compile_module("storage_size").unwrap(); - - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(30_000) - .build_and_unwrap_contract(); - get_contract(&addr); - - // Call contract with allowed storage value. - assert_ok!(builder::call(addr) - .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer - .data(limits::PAYLOAD_BYTES.encode()) - .build()); - - // Call contract with too large a storage value. - assert_err_ignore_postinfo!( - builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), - Error::::ValueTooLarge, - ); - }); -} - -#[test] -fn clear_storage_on_zero_value() { - let (code, _code_hash) = compile_module("clear_storage_on_zero_value").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - builder::bare_call(addr).build_and_unwrap_result(); - }); -} - -#[test] -fn transient_storage_work() { - let (code, _code_hash) = compile_module("transient_storage").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - builder::bare_call(addr).build_and_unwrap_result(); - }); -} - -#[test] -fn transient_storage_limit_in_call() { - let (binary_caller, _code_hash_caller) = - compile_module("create_transient_storage_and_call").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("set_transient_storage").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - // Call contracts with storage values within the limit. - // Caller and Callee contracts each set a transient storage value of size 100. - assert_ok!(builder::call(addr_caller) - .data((100u32, 100u32, &addr_callee).encode()) - .build(),); - - // Call a contract with a storage value that is too large. - // Limit exceeded in the caller contract. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((4u32 * 1024u32, 200u32, &addr_callee).encode()) - .build(), - >::OutOfTransientStorage, - ); - - // Call a contract with a storage value that is too large. - // Limit exceeded in the callee contract. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((50u32, 4 * 1024u32, &addr_callee).encode()) - .build(), - >::ContractTrapped - ); - }); -} - -#[test] -fn deploy_and_call_other_contract() { - let (caller_binary, _caller_code_hash) = compile_module("caller_contract").unwrap(); - let (callee_binary, callee_code_hash) = compile_module("return_with_data").unwrap(); - let code_load_weight = crate::vm::code_load_weight(callee_binary.len() as u32); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr: caller_addr, account_id: caller_account } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - let callee_addr = create2( - &caller_addr, - &callee_binary, - &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in binary - &[0u8; 32], - ); - let callee_account = ::AddressMapper::to_account_id(&callee_addr); - - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - callee_binary, - deposit_limit::(), - ) - .unwrap(); - - // Drop previous events - initialize_block(2); - - // Call BOB contract, which attempts to instantiate and call the callee contract and - // makes various assertions on the results from those calls. - assert_ok!(builder::call(caller_addr) - .data( - (callee_code_hash, code_load_weight.ref_time(), code_load_weight.proof_size()) - .encode() - ) - .build()); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: callee_account.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: callee_account.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: callee_account.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: caller_account.clone(), - to: callee_account.clone(), - amount: 32768 // hardcoded in binary - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: caller_account.clone(), - to: callee_account.clone(), - amount: 32768, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: callee_account.clone(), - transferred: 555, - }), - topics: vec![], - }, - ] - ); - }); -} - -#[test] -fn delegate_call() { - let (caller_binary, _caller_code_hash) = compile_module("delegate_call").unwrap(); - let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); - - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: caller_addr, .. } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(300_000) - .build_and_unwrap_contract(); - - // Instantiate the 'callee' - let Contract { addr: callee_addr, .. } = - builder::bare_instantiate(Code::Upload(callee_binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - assert_ok!(builder::call(caller_addr) - .value(1337) - .data((callee_addr, u64::MAX, u64::MAX).encode()) - .build()); - }); -} - -#[test] -fn delegate_call_non_existant_is_noop() { - let (caller_binary, _caller_code_hash) = compile_module("delegate_call_simple").unwrap(); - - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: caller_addr, .. } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(300_000) - .build_and_unwrap_contract(); - - assert_ok!(builder::call(caller_addr) - .value(1337) - .data((BOB_ADDR, u64::MAX, u64::MAX).encode()) - .build()); - - assert_eq!(test_utils::get_balance(&BOB_FALLBACK), 0); - }); -} - -#[test] -fn delegate_call_with_weight_limit() { - let (caller_binary, _caller_code_hash) = compile_module("delegate_call").unwrap(); - let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); - - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: caller_addr, .. } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(300_000) - .build_and_unwrap_contract(); - - // Instantiate the 'callee' - let Contract { addr: callee_addr, .. } = - builder::bare_instantiate(Code::Upload(callee_binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - // fails, not enough weight - assert_err!( - builder::bare_call(caller_addr) - .native_value(1337) - .data((callee_addr, 100u64, 100u64).encode()) - .build() - .result, - Error::::ContractTrapped, - ); - - assert_ok!(builder::call(caller_addr) - .value(1337) - .data((callee_addr, 500_000_000u64, 100_000u64).encode()) - .build()); - }); -} - -#[test] -fn delegate_call_with_deposit_limit() { - let (caller_binary, _caller_code_hash) = compile_module("delegate_call_deposit_limit").unwrap(); - let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); - - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: caller_addr, .. } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(300_000) - .build_and_unwrap_contract(); - - // Instantiate the 'callee' - let Contract { addr: callee_addr, .. } = - builder::bare_instantiate(Code::Upload(callee_binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - // Delegate call will write 1 storage and deposit of 2 (1 item) + 32 (bytes) is required. - // + 32 + 16 for blake2_128concat - // Fails, not enough deposit - let ret = builder::bare_call(caller_addr) - .native_value(1337) - .data((callee_addr, 81u64).encode()) - .build_and_unwrap_result(); - assert_return_code!(ret, RuntimeReturnCode::OutOfResources); - - assert_ok!(builder::call(caller_addr) - .value(1337) - .data((callee_addr, 82u64).encode()) - .build()); - }); -} - -#[test] -fn transfer_expendable_cannot_kill_account() { - let (binary, _code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(1_000) - .build_and_unwrap_contract(); - - // Check that the BOB contract has been instantiated. - get_contract(&addr); - - let account = ::AddressMapper::to_account_id(&addr); - let total_balance = ::Currency::total_balance(&account); - - assert_eq!( - test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account), - test_utils::contract_base_deposit(&addr) - ); - - // Some or the total balance is held, so it can't be transferred. - assert_err!( - <::Currency as Mutate>::transfer( - &account, - &ALICE, - total_balance, - Preservation::Expendable, - ), - TokenError::FundsUnavailable, - ); - - assert_eq!(::Currency::total_balance(&account), total_balance); - }); -} - -#[test] -fn cannot_self_destruct_through_draining() { - let (binary, _code_hash) = compile_module("drain").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let value = 1_000; - let min_balance = Contracts::min_balance(); - - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(value) - .build_and_unwrap_contract(); - let account = ::AddressMapper::to_account_id(&addr); - - // Check that the BOB contract has been instantiated. - get_contract(&addr); - - // Call BOB which makes it send all funds to the zero address - // The contract code asserts that the transfer fails with the correct error code - assert_ok!(builder::call(addr).build()); - - // Make sure the account wasn't remove by sending all free balance away. - assert_eq!( - ::Currency::total_balance(&account), - value + test_utils::contract_base_deposit(&addr) + min_balance, - ); - }); -} - -#[test] -fn cannot_self_destruct_through_storage_refund_after_price_change() { - let (binary, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Instantiate the BOB contract. - let contract = builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - let info_deposit = test_utils::contract_base_deposit(&contract.addr); - - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit); - assert_eq!(get_contract(&contract.addr).extra_deposit(), 0); - assert_eq!( - ::Currency::total_balance(&contract.account_id), - info_deposit + min_balance - ); - - // Create 100 (16 + 32 bytes for key for blake128 concat) bytes of storage with a - // price of per byte and a single storage item of price 2 - assert_ok!(builder::call(contract.addr).data(100u32.to_le_bytes().to_vec()).build()); - assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit + 100 + 16 + 32 + 2); - - // Increase the byte price and trigger a refund. This should not have any influence - // because the removal is pro rata and exactly those 100 bytes should have been - // removed as we didn't delete the key. - DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); - assert_ok!(builder::call(contract.addr).data(0u32.to_le_bytes().to_vec()).build()); - - // Make sure the account wasn't removed by the refund - assert_eq!( - ::Currency::total_balance(&contract.account_id), - get_contract(&contract.addr).total_deposit() + min_balance, - ); - // + 1 because due to fixed point arithmetic we can sometimes refund - // one unit to little - assert_eq!(get_contract(&contract.addr).extra_deposit(), 16 + 32 + 2 + 1); - }); -} - -#[test] -fn cannot_self_destruct_while_live() { - let (binary, _code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - // Check that the BOB contract has been instantiated. - get_contract(&addr); - - // Call BOB with input data, forcing it make a recursive call to itself to - // self-destruct, resulting in a trap. - assert_err_ignore_postinfo!( - builder::call(addr).data(vec![0]).build(), - Error::::ContractTrapped, - ); - - // Check that BOB is still there. - get_contract(&addr); - }); -} - -#[test] -fn self_destruct_works() { - let (binary, code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(1_000).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&DJANGO_FALLBACK, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Instantiate the BOB contract. - let contract = builder::bare_instantiate(Code::Upload(binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - let hold_balance = test_utils::contract_base_deposit(&contract.addr); - - // Check that the BOB contract has been instantiated. - let _ = get_contract(&contract.addr); - - // Drop all previous events - initialize_block(2); - - // Call BOB without input data which triggers termination. - assert_matches!(builder::call(contract.addr).build(), Ok(_)); - - // Check that code is still there but refcount dropped to zero. - assert_refcount!(&code_hash, 0); - - // Check that account is gone - assert!(get_contract_checked(&contract.addr).is_none()); - assert_eq!(::Currency::total_balance(&contract.account_id), 0); - - // Check that the beneficiary (django) got remaining balance. - assert_eq!( - ::Currency::free_balance(DJANGO_FALLBACK), - 1_000_000 + 100_000 + min_balance - ); - - // Check that the Alice is missing Django's benefit. Within ALICE's total balance - // there's also the code upload deposit held. - assert_eq!( - ::Currency::total_balance(&ALICE), - 1_000_000 - (100_000 + min_balance) - ); - - pretty_assertions::assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: contract.account_id.clone(), - dest: ALICE, - amount: hold_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::KilledAccount { - account: contract.account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: contract.account_id.clone(), - to: DJANGO_FALLBACK, - amount: 100_000 + min_balance, - }), - topics: vec![], - }, - ], - ); - }); -} - -// This tests that one contract cannot prevent another from self-destructing by sending it -// additional funds after it has been drained. -#[test] -fn destroy_contract_and_transfer_funds() { - let (callee_binary, callee_code_hash) = compile_module("self_destruct").unwrap(); - let (caller_binary, _caller_code_hash) = compile_module("destroy_and_transfer").unwrap(); - - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create code hash for bob to instantiate - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - callee_binary.clone(), - deposit_limit::(), - ) - .unwrap(); - - // This deploys the BOB contract, which in turn deploys the CHARLIE contract during - // construction. - let Contract { addr: addr_bob, .. } = - builder::bare_instantiate(Code::Upload(caller_binary)) - .native_value(200_000) - .data(callee_code_hash.as_ref().to_vec()) - .build_and_unwrap_contract(); - - // Check that the CHARLIE contract has been instantiated. - let salt = [47; 32]; // hard coded in fixture. - let addr_charlie = create2(&addr_bob, &callee_binary, &[], &salt); - get_contract(&addr_charlie); - - // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. - assert_ok!(builder::call(addr_bob).data(addr_charlie.encode()).build()); - - // Check that CHARLIE has moved on to the great beyond (ie. died). - assert!(get_contract_checked(&addr_charlie).is_none()); - }); -} - -#[test] -fn cannot_self_destruct_in_constructor() { - let (binary, _) = compile_module("self_destructing_constructor").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Fail to instantiate the BOB because the constructor calls seal_terminate. - assert_err_ignore_postinfo!( - builder::instantiate_with_code(binary).value(100_000).build(), - Error::::TerminatedInConstructor, - ); - }); -} - -#[test] -fn crypto_hash_keccak_256() { - let (binary, _code_hash) = compile_module("crypto_hash_keccak_256").unwrap(); - - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the CRYPTO_HASH_KECCAK_256 contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - // Perform the call. - let input = b"_DEAD_BEEF"; - use sp_io::hashing::*; - // Wraps a hash function into a more dynamic form usable for testing. - macro_rules! dyn_hash_fn { - ($name:ident) => { - Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice()) - }; - } - // The hash function and its associated output byte lengths. - let hash_fn: Box Box<[u8]>> = dyn_hash_fn!(keccak_256); - let expected_size: usize = 32; - // Test the hash function for the input: "_DEAD_BEEF" - let result = builder::bare_call(addr).data(input.to_vec()).build_and_unwrap_result(); - assert!(!result.did_revert()); - let expected = hash_fn(input.as_ref()); - assert_eq!(&result.data[..expected_size], &*expected); - }) -} - -#[test] -fn transfer_return_code() { - let (binary, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let contract = builder::bare_instantiate(Code::Upload(binary)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - // Contract has only the minimal balance so any transfer will fail. - ::Currency::set_balance(&contract.account_id, min_balance); - let result = builder::bare_call(contract.addr).build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - }); -} - -#[test] -fn call_return_code() { - use test_utils::u256_bytes; - - let (caller_code, _caller_hash) = compile_module("call_return_code").unwrap(); - let (callee_code, _callee_hash) = compile_module("ok_trap_revert").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - - let bob = builder::bare_instantiate(Code::Upload(caller_code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - // BOB cannot pay the ed which is needed to pull DJANGO into existence - // this does trap the caller instead of returning an error code - // reasoning is that this error state does not exist on eth where - // ed does not exist. We hide this fact from the contract. - let result = builder::bare_call(bob.addr) - .data((DJANGO_ADDR, u256_bytes(1)).encode()) - .origin(RuntimeOrigin::signed(BOB)) - .build(); - assert_err!(result.result, >::StorageDepositNotEnoughFunds); - - // Contract calls into Django which is no valid contract - // This will be a balance transfer into a new account - // with more than the contract has which will make the transfer fail - let value = Pallet::::convert_native_to_evm(min_balance * 200); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&DJANGO_ADDR) - .iter() - .chain(&value.to_little_endian()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - - // Sending below the minimum balance should result in success. - // The ED is charged from the call origin. - let alice_before = test_utils::get_balance(&ALICE_FALLBACK); - assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), 0); - - let value = Pallet::::convert_native_to_evm(1u64); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&DJANGO_ADDR) - .iter() - .chain(&value.to_little_endian()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::Success); - assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), min_balance + 1); - assert_eq!(test_utils::get_balance(&ALICE_FALLBACK), alice_before - min_balance); - - let django = builder::bare_instantiate(Code::Upload(callee_code)) - .origin(RuntimeOrigin::signed(CHARLIE)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - // Sending more than the contract has will make the transfer fail. - let value = Pallet::::convert_native_to_evm(min_balance * 300); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&value.to_little_endian()) - .chain(&0u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - - // Contract has enough balance but callee reverts because "1" is passed. - ::Currency::set_balance(&bob.account_id, min_balance + 1000); - let value = Pallet::::convert_native_to_evm(5u64); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&value.to_little_endian()) - .chain(&1u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeReverted); - - // Contract has enough balance but callee traps because "2" is passed. - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&value.to_little_endian()) - .chain(&2u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); - }); -} - -#[test] -fn instantiate_return_code() { - let (caller_code, _caller_hash) = compile_module("instantiate_return_code").unwrap(); - let (callee_code, callee_hash) = compile_module("ok_trap_revert").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - let callee_hash = callee_hash.as_ref().to_vec(); - - assert_ok!(builder::instantiate_with_code(callee_code).value(min_balance * 100).build()); - - let contract = builder::bare_instantiate(Code::Upload(caller_code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - // bob cannot pay the ED to create the contract as he has no money - // this traps the caller rather than returning an error - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) - .origin(RuntimeOrigin::signed(BOB)) - .build(); - assert_err!(result.result, >::StorageDepositNotEnoughFunds); - - // Contract has only the minimal balance so any transfer will fail. - ::Currency::set_balance(&contract.account_id, min_balance); - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - - // Contract has enough balance but the passed code hash is invalid - ::Currency::set_balance(&contract.account_id, min_balance + 10_000); - let result = builder::bare_call(contract.addr).data(vec![0; 36]).build(); - assert_err!(result.result, >::CodeNotFound); - - // Contract has enough balance but callee reverts because "1" is passed. - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeReverted); - - // Contract has enough balance but callee traps because "2" is passed. - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); - - // Contract instantiation succeeds - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, 0); - - // Contract instantiation fails because the same salt is being used again. - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::DuplicateContractAddress); - }); -} - -#[test] -fn lazy_removal_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let contract = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - let info = get_contract(&contract.addr); - let trie = &info.child_trie_info(); - - // Put value into the contracts child trie - child::put(trie, &[99], &42); - - // Terminate the contract - assert_ok!(builder::call(contract.addr).build()); - - // Contract info should be gone - assert!(!>::contains_key(&contract.addr)); - - // But value should be still there as the lazy removal did not run, yet. - assert_matches!(child::get(trie, &[99]), Some(42)); - - // Run the lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); - - // Value should be gone now - assert_matches!(child::get::(trie, &[99]), None); - }); -} - -#[test] -fn lazy_batch_removal_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let mut tries: Vec = vec![]; - - for i in 0..3u8 { - let contract = builder::bare_instantiate(Code::Upload(code.clone())) - .native_value(min_balance * 100) - .salt(Some([i; 32])) - .build_and_unwrap_contract(); - - let info = get_contract(&contract.addr); - let trie = &info.child_trie_info(); - - // Put value into the contracts child trie - child::put(trie, &[99], &42); - - // Terminate the contract. Contract info should be gone, but value should be still - // there as the lazy removal did not run, yet. - assert_ok!(builder::call(contract.addr).build()); - - assert!(!>::contains_key(&contract.addr)); - assert_matches!(child::get(trie, &[99]), Some(42)); - - tries.push(trie.clone()) - } - - // Run single lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); - - // The single lazy removal should have removed all queued tries - for trie in tries.iter() { - assert_matches!(child::get::(trie, &[99]), None); - } - }); -} - -#[test] -fn ref_time_left_api_works() { - let (code, _) = compile_module("ref_time_left").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor calls ref_time_left twice and asserts it to decrease - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It echoes back the ref_time returned by the ref_time_left API. - let received = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - - let returned_value = u64::from_le_bytes(received.data[..8].try_into().unwrap()); - assert!(returned_value > 0); - assert!(returned_value < GAS_LIMIT.ref_time()); - }); -} - -#[test] -fn lazy_removal_partial_remove_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - - // We create a contract with some extra keys above the weight limit - let extra_keys = 7u32; - let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); - let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); - let vals: Vec<_> = (0..max_keys + extra_keys) - .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) - .collect(); - - let mut ext = ExtBuilder::default().existential_deposit(50).build(); - - let trie = ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - let info = get_contract(&addr); - - // Put value into the contracts child trie - for val in &vals { - info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); - } - AccountInfo::::insert_contract(&addr, info.clone()); - - // Terminate the contract - assert_ok!(builder::call(addr).build()); - - // Contract info should be gone - assert!(!>::contains_key(&addr)); - - let trie = info.child_trie_info(); - - // But value should be still there as the lazy removal did not run, yet. - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); - } - - trie.clone() - }); - - // The lazy removal limit only applies to the backend but not to the overlay. - // This commits all keys from the overlay to the backend. - ext.commit_all().unwrap(); - - ext.execute_with(|| { - // Run the lazy removal - ContractInfo::::process_deletion_queue_batch(&mut meter); - - // Weight should be exhausted because we could not even delete all keys - assert!(!meter.can_consume(weight_per_key)); - - let mut num_deleted = 0u32; - let mut num_remaining = 0u32; - - for val in &vals { - match child::get::(&trie, &blake2_256(&val.0)) { - None => num_deleted += 1, - Some(x) if x == val.1 => num_remaining += 1, - Some(_) => panic!("Unexpected value in contract storage"), - } - } - - // All but one key is removed - assert_eq!(num_deleted + num_remaining, vals.len() as u32); - assert_eq!(num_deleted, max_keys); - assert_eq!(num_remaining, extra_keys); - }); -} - -#[test] -fn lazy_removal_does_no_run_on_low_remaining_weight() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - let info = get_contract(&addr); - let trie = &info.child_trie_info(); - - // Put value into the contracts child trie - child::put(trie, &[99], &42); - - // Terminate the contract - assert_ok!(builder::call(addr).build()); - - // Contract info should be gone - assert!(!>::contains_key(&addr)); - - // But value should be still there as the lazy removal did not run, yet. - assert_matches!(child::get(trie, &[99]), Some(42)); - - // Assign a remaining weight which is too low for a successful deletion of the contract - let low_remaining_weight = - <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - - // Run the lazy removal - Contracts::on_idle(System::block_number(), low_remaining_weight); - - // Value should still be there, since remaining weight was too low for removal - assert_matches!(child::get::(trie, &[99]), Some(42)); - - // Run the lazy removal while deletion_queue is not full - Contracts::on_initialize(System::block_number()); - - // Value should still be there, since deletion_queue was not full - assert_matches!(child::get::(trie, &[99]), Some(42)); - - // Run on_idle with max remaining weight, this should remove the value - Contracts::on_idle(System::block_number(), Weight::MAX); - - // Value should be gone - assert_matches!(child::get::(trie, &[99]), None); - }); -} - -#[test] -fn lazy_removal_does_not_use_all_weight() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - - let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); - let mut ext = ExtBuilder::default().existential_deposit(50).build(); - - let (trie, vals, weight_per_key) = ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - let info = get_contract(&addr); - let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); - assert!(max_keys > 0); - - // We create a contract with one less storage item than we can remove within the limit - let vals: Vec<_> = (0..max_keys - 1) - .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) - .collect(); - - // Put value into the contracts child trie - for val in &vals { - info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); - } - AccountInfo::::insert_contract(&addr, info.clone()); - - // Terminate the contract - assert_ok!(builder::call(addr).build()); - - // Contract info should be gone - assert!(!>::contains_key(&addr)); - - let trie = info.child_trie_info(); - - // But value should be still there as the lazy removal did not run, yet. - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); - } - - (trie, vals, weight_per_key) - }); - - // The lazy removal limit only applies to the backend but not to the overlay. - // This commits all keys from the overlay to the backend. - ext.commit_all().unwrap(); - - ext.execute_with(|| { - // Run the lazy removal - ContractInfo::::process_deletion_queue_batch(&mut meter); - let base_weight = - <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - assert_eq!(meter.consumed(), weight_per_key.mul(vals.len() as _) + base_weight); - - // All the keys are removed - for val in vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); - } - }); -} - -#[test] -fn deletion_queue_ring_buffer_overflow() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - let mut ext = ExtBuilder::default().existential_deposit(50).build(); - - // setup the deletion queue with custom counters - ext.execute_with(|| { - let queue = DeletionQueueManager::from_test_values(u32::MAX - 1, u32::MAX - 1); - >::set(queue); - }); - - // commit the changes to the storage - ext.commit_all().unwrap(); - - ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let mut tries: Vec = vec![]; - - // add 3 contracts to the deletion queue - for i in 0..3u8 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) - .native_value(min_balance * 100) - .salt(Some([i; 32])) - .build_and_unwrap_contract(); - - let info = get_contract(&addr); - let trie = &info.child_trie_info(); - - // Put value into the contracts child trie - child::put(trie, &[99], &42); - - // Terminate the contract. Contract info should be gone, but value should be still - // there as the lazy removal did not run, yet. - assert_ok!(builder::call(addr).build()); - - assert!(!>::contains_key(&addr)); - assert_matches!(child::get(trie, &[99]), Some(42)); - - tries.push(trie.clone()) - } - - // Run single lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); - - // The single lazy removal should have removed all queued tries - for trie in tries.iter() { - assert_matches!(child::get::(trie, &[99]), None); - } - - // insert and delete counter values should go from u32::MAX - 1 to 1 - assert_eq!(>::get().as_test_tuple(), (1, 1)); - }) -} -#[test] -fn refcounter() { - let (binary, code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Create two contracts with the same code and check that they do in fact share it. - let Contract { addr: addr0, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) - .native_value(min_balance * 100) - .salt(Some([0; 32])) - .build_and_unwrap_contract(); - let Contract { addr: addr1, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) - .native_value(min_balance * 100) - .salt(Some([1; 32])) - .build_and_unwrap_contract(); - assert_refcount!(code_hash, 2); - - // Sharing should also work with the usual instantiate call - let Contract { addr: addr2, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .native_value(min_balance * 100) - .salt(Some([2; 32])) - .build_and_unwrap_contract(); - assert_refcount!(code_hash, 3); - - // Terminating one contract should decrement the refcount - assert_ok!(builder::call(addr0).build()); - assert_refcount!(code_hash, 2); - - // remove another one - assert_ok!(builder::call(addr1).build()); - assert_refcount!(code_hash, 1); - - // Pristine code should still be there - PristineCode::::get(code_hash).unwrap(); - - // remove the last contract - assert_ok!(builder::call(addr2).build()); - assert_refcount!(code_hash, 0); - - // refcount is `0` but code should still exists because it needs to be removed manually - assert!(crate::PristineCode::::contains_key(&code_hash)); - }); -} - -#[test] -fn gas_estimation_for_subcalls() { - let (caller_code, _caller_hash) = compile_module("call_with_limit").unwrap(); - let (dummy_code, _callee_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); - - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(caller_code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - let Contract { addr: addr_dummy, .. } = builder::bare_instantiate(Code::Upload(dummy_code)) - .native_value(min_balance * 100) - .build_and_unwrap_contract(); - - // Run the test for all of those weight limits for the subcall - let weights = [ - Weight::MAX, - GAS_LIMIT, - GAS_LIMIT * 2, - GAS_LIMIT / 5, - Weight::from_parts(u64::MAX, GAS_LIMIT.proof_size()), - Weight::from_parts(GAS_LIMIT.ref_time(), u64::MAX), - ]; - - let (sub_addr, sub_input) = (addr_dummy.as_ref(), vec![]); - - for weight in weights { - let input: Vec = sub_addr - .iter() - .cloned() - .chain(weight.ref_time().to_le_bytes()) - .chain(weight.proof_size().to_le_bytes()) - .chain(sub_input.clone()) - .collect(); - - // Call in order to determine the gas that is required for this call - let result_orig = builder::bare_call(addr_caller).data(input.clone()).build(); - assert_ok!(&result_orig.result); - assert_eq!(result_orig.gas_required, result_orig.gas_consumed); - - // Make the same call using the estimated gas. Should succeed. - let result = builder::bare_call(addr_caller) - .gas_limit(result_orig.gas_required) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) - .data(input.clone()) - .build(); - assert_ok!(&result.result); - - // Check that it fails with too little ref_time - let result = builder::bare_call(addr_caller) - .gas_limit(result_orig.gas_required.sub_ref_time(1)) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) - .data(input.clone()) - .build(); - assert_err!(result.result, >::OutOfGas); - - // Check that it fails with too little proof_size - let result = builder::bare_call(addr_caller) - .gas_limit(result_orig.gas_required.sub_proof_size(1)) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) - .data(input.clone()) - .build(); - assert_err!(result.result, >::OutOfGas); - } - }); -} - -#[test] -fn call_runtime_reentrancy_guarded() { - use crate::precompiles::Precompile; - use alloy_core::sol_types::SolInterface; - use precompiles::{INoInfo, NoInfo}; - - let precompile_addr = H160(NoInfo::::MATCHER.base_address()); - - let (callee_code, _callee_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(callee_code)) - .native_value(min_balance * 100) - .salt(Some([1; 32])) - .build_and_unwrap_contract(); - - // Call pallet_revive call() dispatchable - let call = RuntimeCall::Contracts(crate::Call::call { - dest: addr_callee, - value: 0, - gas_limit: GAS_LIMIT / 3, - storage_deposit_limit: deposit_limit::(), - data: vec![], - }) - .encode(); - - // Call runtime to re-enter back to contracts engine by - // calling dummy contract - let result = builder::bare_call(precompile_addr) - .data( - INoInfo::INoInfoCalls::callRuntime(INoInfo::callRuntimeCall { call: call.into() }) - .abi_encode(), - ) - .build(); - // Call to runtime should fail because of the re-entrancy guard - assert_err!(result.result, >::ReenteredPallet); - }); -} - -#[test] -fn sr25519_verify() { - let (binary, _code_hash) = compile_module("sr25519_verify").unwrap(); - - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the sr25519_verify contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(100_000) - .build_and_unwrap_contract(); - - let call_with = |message: &[u8; 11]| { - // Alice's signature for "hello world" - #[rustfmt::skip] - let signature: [u8; 64] = [ - 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247, - 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83, - 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255, - 228, 54, 115, 63, 30, 207, 205, 131, - ]; - - // Alice's public key - #[rustfmt::skip] - let public_key: [u8; 32] = [ - 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, - 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125, - ]; - - let mut params = vec![]; - params.extend_from_slice(&signature); - params.extend_from_slice(&public_key); - params.extend_from_slice(message); - - builder::bare_call(addr).data(params).build_and_unwrap_result() - }; - - // verification should succeed for "hello world" - assert_return_code!(call_with(&b"hello world"), RuntimeReturnCode::Success); - - // verification should fail for other messages - assert_return_code!(call_with(&b"hello worlD"), RuntimeReturnCode::Sr25519VerifyFailed); - }); -} - -#[test] -fn upload_code_works() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert!(!PristineCode::::contains_key(&code_hash)); - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - expected_deposit(ensure_stored(code_hash)); - }); -} - -#[test] -fn upload_code_limit_too_low() { - let (binary, _code_hash) = compile_module("dummy").unwrap(); - let deposit_expected = expected_deposit(binary.len()); - let deposit_insufficient = deposit_expected.saturating_sub(1); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_insufficient,), - >::StorageDepositLimitExhausted, - ); - - assert_eq!(System::events(), vec![]); - }); -} - -#[test] -fn upload_code_not_enough_balance() { - let (binary, _code_hash) = compile_module("dummy").unwrap(); - let deposit_expected = expected_deposit(binary.len()); - let deposit_insufficient = deposit_expected.saturating_sub(1); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, deposit_insufficient); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,), - >::StorageDepositNotEnoughFunds, - ); - - assert_eq!(System::events(), vec![]); - }); -} - -#[test] -fn remove_code_works() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - expected_deposit(ensure_stored(code_hash)); - assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); - }); -} - -#[test] -fn remove_code_wrong_origin() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - expected_deposit(ensure_stored(code_hash)); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), - sp_runtime::traits::BadOrigin, - ); - }); -} - -#[test] -fn remove_code_in_use() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - assert_ok!(builder::instantiate_with_code(binary).build()); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), - >::CodeInUse, - ); - - assert_eq!(System::events(), vec![]); - }); -} - -#[test] -fn remove_code_not_found() { - let (_binary, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), - >::CodeNotFound, - ); - - assert_eq!(System::events(), vec![]); - }); -} - -#[test] -fn instantiate_with_zero_balance_works() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Drop previous events - initialize_block(2); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - // Ensure the contract was stored and get expected deposit amount to be reserved. - expected_deposit(ensure_stored(code_hash)); - - // Make sure the account exists even though no free balance was send - assert_eq!(::Currency::free_balance(&account_id), min_balance); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + test_utils::contract_base_deposit(&addr) - ); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Held { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::CodeUploadDepositReserve, - ), - who: ALICE, - amount: 776, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone(), - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: account_id, - transferred: 336, - }), - topics: vec![], - }, - ] - ); - }); -} - -#[test] -fn instantiate_with_below_existential_deposit_works() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let value = 50; - - // Drop previous events - initialize_block(2); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(value) - .build_and_unwrap_contract(); - - // Ensure the contract was stored and get expected deposit amount to be reserved. - expected_deposit(ensure_stored(code_hash)); - // Make sure the account exists even though not enough free balance was send - assert_eq!(::Currency::free_balance(&account_id), min_balance + value); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + value + test_utils::contract_base_deposit(&addr) - ); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Held { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::CodeUploadDepositReserve, - ), - who: ALICE, - amount: 776, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: 50, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: account_id.clone(), - transferred: 336, - }), - topics: vec![], - }, - ] - ); - }); -} - -#[test] -fn storage_deposit_works() { - let (binary, _code_hash) = compile_module("multi_store").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - let mut deposit = test_utils::contract_base_deposit(&addr); - - // Drop previous events - initialize_block(2); - - // Create storage - assert_ok!(builder::call(addr).value(42).data((50u32, 20u32).encode()).build()); - // 4 is for creating 2 storage items - // 48 is for each of the keys - let charged0 = 4 + 50 + 20 + 48 + 48; - deposit += charged0; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - // Add more storage (but also remove some) - assert_ok!(builder::call(addr).data((100u32, 10u32).encode()).build()); - let charged1 = 50 - 10; - deposit += charged1; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - // Remove more storage (but also add some) - assert_ok!(builder::call(addr).data((10u32, 20u32).encode()).build()); - // -1 for numeric instability - let refunded0 = 90 - 10 - 1; - deposit -= refunded0; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: 42, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: account_id.clone(), - transferred: charged0, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: ALICE, - dest: account_id.clone(), - transferred: charged1, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { - reason: ::RuntimeHoldReason::Contracts( - HoldReason::StorageDepositReserve, - ), - source: account_id.clone(), - dest: ALICE, - amount: refunded0, - }), - topics: vec![], - }, - ] - ); - }); -} - -#[test] -fn storage_deposit_callee_works() { - let (binary_caller, _code_hash_caller) = compile_module("call").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - assert_ok!(builder::call(addr_caller).data((100u32, &addr_callee).encode()).build()); - - let callee = get_contract(&addr_callee); - let deposit = DepositPerByte::get() * 100 + DepositPerItem::get() * 1 + 48; - - assert_eq!(Pallet::::evm_balance(&addr_caller), U256::zero()); - assert_eq!( - callee.total_deposit(), - deposit + test_utils::contract_base_deposit(&addr_callee) - ); - }); -} - -#[test] -fn set_code_extrinsic() { - let (binary, code_hash) = compile_module("dummy").unwrap(); - let (new_binary, new_code_hash) = compile_module("crypto_hash_keccak_256").unwrap(); - - assert_ne!(code_hash, new_code_hash); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - new_binary, - deposit_limit::(), - )); - - // Drop previous events - initialize_block(2); - - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - - // only root can execute this extrinsic - assert_noop!( - Contracts::set_code(RuntimeOrigin::signed(ALICE), addr, new_code_hash), - sp_runtime::traits::BadOrigin, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // contract must exist - assert_noop!( - Contracts::set_code(RuntimeOrigin::root(), BOB_ADDR, new_code_hash), - >::ContractNotFound, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // new code hash must exist - assert_noop!( - Contracts::set_code(RuntimeOrigin::root(), addr, Default::default()), - >::CodeNotFound, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // successful call - assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr, new_code_hash)); - assert_eq!(get_contract(&addr).code_hash, new_code_hash); - assert_refcount!(&code_hash, 0); - assert_refcount!(&new_code_hash, 1); - }); -} - -#[test] -fn slash_cannot_kill_account() { - let (binary, _code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let value = 700; - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(value) - .build_and_unwrap_contract(); - - // Drop previous events - initialize_block(2); - - let info_deposit = test_utils::contract_base_deposit(&addr); - - assert_eq!( - test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id), - info_deposit - ); - - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + value + min_balance - ); - - // Try to destroy the account of the contract by slashing the total balance. - // The account does not get destroyed because slashing only affects the balance held - // under certain `reason`. Slashing can for example happen if the contract takes part - // in staking. - let _ = ::Currency::slash( - &HoldReason::StorageDepositReserve.into(), - &account_id, - ::Currency::total_balance(&account_id), - ); - - // Slashing only removed the balance held. - assert_eq!(::Currency::total_balance(&account_id), value + min_balance); - }); -} - -#[test] -fn contract_reverted() { - let (binary, code_hash) = compile_module("return_with_data").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let flags = ReturnFlags::REVERT; - let buffer = [4u8, 8, 15, 16, 23, 42]; - let input = (flags.bits(), buffer).encode(); - - // We just upload the code for later use - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - binary.clone(), - deposit_limit::(), - )); - - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).data(input.clone()).build(), - >::ContractReverted, - ); - - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::instantiate_with_code(binary).data(input.clone()).build(), - >::ContractReverted, - ); - - // Calling directly: revert leads to success but the flags indicate the error - // This is just a different way of transporting the error that allows the read out - // the `data` which is only there on success. Obviously, the contract isn't - // instantiated. - let result = builder::bare_instantiate(Code::Existing(code_hash)) - .data(input.clone()) - .build_and_unwrap_result(); - assert_eq!(result.result.flags, flags); - assert_eq!(result.result.data, buffer); - assert!(!>::contains_key(result.addr)); - - // Pass empty flags and therefore successfully instantiate the contract for later use. - let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .data(ReturnFlags::empty().bits().encode()) - .build_and_unwrap_contract(); - - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::call(addr).data(input.clone()).build(), - >::ContractReverted, - ); - - // Calling directly: revert leads to success but the flags indicate the error - let result = builder::bare_call(addr).data(input).build_and_unwrap_result(); - assert_eq!(result.flags, flags); - assert_eq!(result.data, buffer); - }); -} - -#[test] -fn set_code_hash() { - let (binary, _) = compile_module("set_code_hash").unwrap(); - let (new_binary, new_code_hash) = compile_module("new_set_code_hash_contract").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: contract_addr, .. } = builder::bare_instantiate(Code::Upload(binary)) - .native_value(300_000) - .build_and_unwrap_contract(); - // upload new code - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - new_binary.clone(), - deposit_limit::(), - )); - - System::reset_events(); - - // First call sets new code_hash and returns 1 - let result = builder::bare_call(contract_addr) - .data(new_code_hash.as_ref().to_vec()) - .build_and_unwrap_result(); - assert_return_code!(result, 1); - - // Second calls new contract code that returns 2 - let result = builder::bare_call(contract_addr).build_and_unwrap_result(); - assert_return_code!(result, 2); - }); -} - -#[test] -fn storage_deposit_limit_is_enforced() { - let (binary, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Setting insufficient storage_deposit should fail. - assert_err!( - builder::bare_instantiate(Code::Upload(binary.clone())) - // expected deposit is 2 * ed + 3 for the call - .storage_deposit_limit((2 * min_balance + 3 - 1).into()) - .build() - .result, - >::StorageDepositLimitExhausted, - ); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - let info_deposit = test_utils::contract_base_deposit(&addr); - // Check that the BOB contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + min_balance - ); - - // Create 1 byte of storage with a price of per byte, - // setting insufficient deposit limit, as it requires 3 Balance: - // 2 for the item added + 1 (value) + 48 (key) - assert_err_ignore_postinfo!( - builder::call(addr) - .storage_deposit_limit(50) - .data(1u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - - // now with enough limit - assert_ok!(builder::call(addr) - .storage_deposit_limit(51) - .data(1u32.to_le_bytes().to_vec()) - .build()); - - // Use 4 more bytes of the storage for the same item, which requires 4 Balance. - // Should fail as DefaultDepositLimit is 3 and hence isn't enough. - assert_err_ignore_postinfo!( - builder::call(addr) - .storage_deposit_limit(3) - .data(5u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - }); -} - -#[test] -fn deposit_limit_in_nested_calls() { - let (binary_caller, _code_hash_caller) = compile_module("create_storage_and_call").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - // Create 100 bytes of storage with a price of per byte - // This is 100 Balance + 2 Balance for the item - // 48 for the key - assert_ok!(builder::call(addr_callee) - .storage_deposit_limit(102 + 48) - .data(100u32.to_le_bytes().to_vec()) - .build()); - - // We do not remove any storage but add a storage item of 12 bytes in the caller - // contract. This would cost 12 + 2 + 72 = 86 Balance. - // The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it. - // This should fail as the specified parent's limit is less than the cost: 13 < - // 14. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(85) - .data((100u32, &addr_callee, U256::MAX).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - - // Now we specify the parent's limit high enough to cover the caller's storage - // additions. However, we use a single byte more in the callee, hence the storage - // deposit should be 87 Balance. - // The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it. - // This should fail as the specified parent's limit is less than the cost: 86 < 87 - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(86) - .data((101u32, &addr_callee, &U256::MAX).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - - // The parents storage deposit limit doesn't matter as the sub calls limit - // is enforced eagerly. However, we set a special deposit limit of 1 Balance for the - // nested call. This should fail as callee adds up 2 bytes to the storage, meaning - // that the nested call should have a deposit limit of at least 2 Balance. The - // sub-call should be rolled back, which is covered by the next test case. - let ret = builder::bare_call(addr_caller) - .storage_deposit_limit(DepositLimit::Balance(u64::MAX)) - .data((102u32, &addr_callee, U256::from(1u64)).encode()) - .build_and_unwrap_result(); - assert_return_code!(ret, RuntimeReturnCode::OutOfResources); - - // Refund in the callee contract but not enough to cover the Balance required by the - // caller. Note that if previous sub-call wouldn't roll back, this call would pass - // making the test case fail. We don't set a special limit for the nested call here. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(0) - .data((87u32, &addr_callee, &U256::MAX.to_little_endian()).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - - let _ = ::Currency::set_balance(&ALICE, 511); - - // Require more than the sender's balance. - // Limit the sub call to little balance so it should fail in there - let ret = builder::bare_call(addr_caller) - .data((416, &addr_callee, U256::from(1u64)).encode()) - .build_and_unwrap_result(); - assert_return_code!(ret, RuntimeReturnCode::OutOfResources); - - // Free up enough storage in the callee so that the caller can create a new item - // We set the special deposit limit of 1 Balance for the nested call, which isn't - // enforced as callee frees up storage. This should pass. - assert_ok!(builder::call(addr_caller) - .storage_deposit_limit(1) - .data((0u32, &addr_callee, U256::from(1u64)).encode()) - .build()); - }); -} - -#[test] -fn deposit_limit_in_nested_instantiate() { - let (binary_caller, _code_hash_caller) = - compile_module("create_storage_and_instantiate").unwrap(); - let (binary_callee, code_hash_callee) = compile_module("store_deploy").unwrap(); - const ED: u64 = 5; - ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 1_000_000); - // Create caller contract - let Contract { addr: addr_caller, account_id: caller_id } = - builder::bare_instantiate(Code::Upload(binary_caller)) - .native_value(10_000) // this balance is later passed to the deployed contract - .build_and_unwrap_contract(); - // Deploy a contract to get its occupied storage size - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary_callee)) - .data(vec![0, 0, 0, 0]) - .build_and_unwrap_contract(); - - // This is the deposit we expect to be charged just for instantiatiting the callee. - // - // - callee_info_len + 2 for storing the new contract info - // - the deposit for depending on a code hash - // - ED for deployed contract account - // - 2 for the storage item of 0 bytes being created in the callee constructor - // - 48 for the key - let callee_min_deposit = { - let callee_info_len = - AccountInfo::::load_contract(&addr).unwrap().encoded_size() as u64; - let code_deposit = test_utils::lockup_deposit(&code_hash_callee); - callee_info_len + code_deposit + 2 + ED + 2 + 48 - }; - - // The parent just stores an item of the passed size so at least - // we need to pay for the item itself. - let caller_min_deposit = callee_min_deposit + 2 + 48; - - // Fail in callee. - // - // We still fail in the sub call because we enforce limits on return from a contract. - // Sub calls return first to they are checked first. - let ret = builder::bare_call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(DepositLimit::Balance(0)) - .data((&code_hash_callee, 100u32, &U256::MAX.to_little_endian()).encode()) - .build_and_unwrap_result(); - assert_return_code!(ret, RuntimeReturnCode::OutOfResources); - // The charges made on instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Fail in the caller. - // - // For that we need to supply enough storage deposit so that the sub call - // succeeds but the parent call runs out of storage. - let ret = builder::bare_call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(DepositLimit::Balance(callee_min_deposit)) - .data((&code_hash_callee, 0u32, &U256::MAX.to_little_endian()).encode()) - .build(); - assert_err!(ret.result, >::StorageDepositLimitExhausted); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Fail in the callee with bytes. - // - // Same as above but stores one byte in both caller and callee. - let ret = builder::bare_call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(DepositLimit::Balance(caller_min_deposit + 1)) - .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit)).encode()) - .build_and_unwrap_result(); - assert_return_code!(ret, RuntimeReturnCode::OutOfResources); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Fail in the caller with bytes. - // - // Same as above but stores one byte in both caller and callee. - let ret = builder::bare_call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(DepositLimit::Balance(callee_min_deposit + 1)) - .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit + 1)).encode()) - .build(); - assert_err!(ret.result, >::StorageDepositLimitExhausted); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Set enough deposit limit for the child instantiate. This should succeed. - let result = builder::bare_call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit((caller_min_deposit + 2).into()) - .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit + 1)).encode()) - .build(); - - let returned = result.result.unwrap(); - assert!(!returned.did_revert()); - - // All balance of the caller except ED has been transferred to the callee. - // No deposit has been taken from it. - assert_eq!(::Currency::free_balance(&caller_id), ED); - // Get address of the deployed contract. - let addr_callee = H160::from_slice(&returned.data[0..20]); - let callee_account_id = ::AddressMapper::to_account_id(&addr_callee); - // 10_000 should be sent to callee from the caller contract, plus ED to be sent from the - // origin. - assert_eq!(::Currency::free_balance(&callee_account_id), 10_000 + ED); - // The origin should be charged with what the outer call consumed - assert_eq!( - ::Currency::free_balance(&BOB), - 1_000_000 - (caller_min_deposit + 2), - ); - assert_eq!(result.storage_deposit.charge_or_zero(), (caller_min_deposit + 2)) - }); -} - -#[test] -fn deposit_limit_honors_liquidity_restrictions() { - let (binary, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let bobs_balance = 1_000; - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, bobs_balance); - let min_balance = Contracts::min_balance(); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - let info_deposit = test_utils::contract_base_deposit(&addr); - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + min_balance - ); - - // check that the hold is honored - ::Currency::hold( - &HoldReason::CodeUploadDepositReserve.into(), - &BOB, - bobs_balance - min_balance, - ) - .unwrap(); - assert_err_ignore_postinfo!( - builder::call(addr) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(10_000) - .data(100u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositNotEnoughFunds, - ); - assert_eq!(::Currency::free_balance(&BOB), min_balance); - }); -} - -#[test] -fn deposit_limit_honors_existential_deposit() { - let (binary, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 300); - let min_balance = Contracts::min_balance(); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - let info_deposit = test_utils::contract_base_deposit(&addr); - - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + info_deposit - ); - - // check that the deposit can't bring the account below the existential deposit - assert_err_ignore_postinfo!( - builder::call(addr) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(10_000) - .data(100u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositNotEnoughFunds, - ); - assert_eq!(::Currency::free_balance(&BOB), 300); - }); -} - -#[test] -fn native_dependency_deposit_works() { - let (binary, code_hash) = compile_module("set_code_hash").unwrap(); - let (dummy_binary, dummy_code_hash) = compile_module("dummy").unwrap(); - - // Test with both existing and uploaded code - for code in [Code::Upload(binary.clone()), Code::Existing(code_hash)] { - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let lockup_deposit_percent = CodeHashLockupDepositPercent::get(); - - // Upload the dummy contract, - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - dummy_binary.clone(), - deposit_limit::(), - ) - .unwrap(); - - // Upload `set_code_hash` contracts if using Code::Existing. - let add_upload_deposit = match code { - Code::Existing(_) => { - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - binary.clone(), - deposit_limit::(), - ) - .unwrap(); - false - }, - Code::Upload(_) => true, - }; - - // Instantiate the set_code_hash contract. - let res = builder::bare_instantiate(code).build(); - - let addr = res.result.unwrap().addr; - let account_id = ::AddressMapper::to_account_id(&addr); - let base_deposit = test_utils::contract_base_deposit(&addr); - let upload_deposit = test_utils::get_code_deposit(&code_hash); - let extra_deposit = add_upload_deposit.then(|| upload_deposit).unwrap_or_default(); - - assert_eq!( - res.storage_deposit.charge_or_zero(), - extra_deposit + base_deposit + Contracts::min_balance() - ); - - // call set_code_hash - builder::bare_call(addr) - .data(dummy_code_hash.encode()) - .build_and_unwrap_result(); - - // Check updated storage_deposit due to code size changes - let deposit_diff = lockup_deposit_percent - .mul_ceil(test_utils::get_code_deposit(&code_hash)) - - lockup_deposit_percent.mul_ceil(test_utils::get_code_deposit(&dummy_code_hash)); - let new_base_deposit = test_utils::contract_base_deposit(&addr); - assert_ne!(deposit_diff, 0); - assert_eq!(base_deposit - new_base_deposit, deposit_diff); - - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &account_id - ), - new_base_deposit - ); - }); - } -} - -#[test] -fn block_hash_works() { - let (code, _) = compile_module("block_hash").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // The genesis config sets to the block number to 1 - let block_hash = [1; 32]; - frame_system::BlockHash::::insert( - &crate::BlockNumberFor::::from(0u32), - ::Hash::from(&block_hash), - ); - assert_ok!(builder::call(addr) - .data((U256::zero(), H256::from(block_hash)).encode()) - .build()); - - // A block number out of range returns the zero value - assert_ok!(builder::call(addr).data((U256::from(1), H256::zero()).encode()).build()); - }); -} - -#[test] -fn block_author_works() { - let (code, _) = compile_module("block_author").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // The fixture asserts the input to match the find_author API method output. - assert_ok!(builder::call(addr).data(EVE_ADDR.encode()).build()); - }); -} - -#[test] -fn root_cannot_upload_code() { - let (binary, _) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::upload_code(RuntimeOrigin::root(), binary, deposit_limit::()), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn root_cannot_remove_code() { - let (_, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::remove_code(RuntimeOrigin::root(), code_hash), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn signed_cannot_set_code() { - let (_, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::set_code(RuntimeOrigin::signed(ALICE), BOB_ADDR, code_hash), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn none_cannot_call_code() { - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::call(BOB_ADDR).origin(RuntimeOrigin::none()).build(), - DispatchError::BadOrigin, - ); - }); -} - -#[test] -fn root_can_call() { - let (binary, _) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); - - // Call the contract. - assert_ok!(builder::call(addr).origin(RuntimeOrigin::root()).build()); - }); -} - -#[test] -fn root_cannot_instantiate_with_code() { - let (binary, _) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::instantiate_with_code(binary).origin(RuntimeOrigin::root()).build(), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn root_cannot_instantiate() { - let (_, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).origin(RuntimeOrigin::root()).build(), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn only_upload_origin_can_upload() { - let (binary, _) = compile_module("dummy").unwrap(); - UploadAccount::set(Some(ALICE)); - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(&BOB, 1_000_000); - - assert_err!( - Contracts::upload_code(RuntimeOrigin::root(), binary.clone(), deposit_limit::(),), - DispatchError::BadOrigin - ); - - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(BOB), - binary.clone(), - deposit_limit::(), - ), - DispatchError::BadOrigin - ); - - // Only alice is allowed to upload contract code. - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - binary.clone(), - deposit_limit::(), - )); - }); -} - -#[test] -fn only_instantiation_origin_can_instantiate() { - let (code, code_hash) = compile_module("dummy").unwrap(); - InstantiateAccount::set(Some(ALICE)); - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(&BOB, 1_000_000); - - assert_err_ignore_postinfo!( - builder::instantiate_with_code(code.clone()) - .origin(RuntimeOrigin::root()) - .build(), - DispatchError::BadOrigin - ); - - assert_err_ignore_postinfo!( - builder::instantiate_with_code(code.clone()) - .origin(RuntimeOrigin::signed(BOB)) - .build(), - DispatchError::BadOrigin - ); - - // Only Alice can instantiate - assert_ok!(builder::instantiate_with_code(code).build()); - - // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).origin(RuntimeOrigin::signed(BOB)).build(), - DispatchError::BadOrigin - ); - }); -} - -#[test] -fn balance_of_api() { - let (binary, _code_hash) = compile_module("balance_of").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(&ALICE_FALLBACK, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); - - // The fixture asserts a non-zero returned free balance of the account; - // The ALICE_FALLBACK account is endowed; - // Hence we should not revert - assert_ok!(builder::call(addr).data(ALICE_ADDR.0.to_vec()).build()); - - // The fixture asserts a non-zero returned free balance of the account; - // The ETH_BOB account is not endowed; - // Hence we should revert - assert_err_ignore_postinfo!( - builder::call(addr).data(BOB_ADDR.0.to_vec()).build(), - >::ContractTrapped - ); - }); -} - -#[test] -fn balance_api_returns_free_balance() { - let (binary, _code_hash) = compile_module("balance").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the BOB contract without any extra balance. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); - - let value = 0; - // Call BOB which makes it call the balance runtime API. - // The contract code asserts that the returned balance is 0. - assert_ok!(builder::call(addr).value(value).build()); - - let value = 1; - // Calling with value will trap the contract. - assert_err_ignore_postinfo!( - builder::call(addr).value(value).build(), - >::ContractTrapped - ); - }); -} - -#[test] -fn call_depth_is_enforced() { - let (binary, _code_hash) = compile_module("recurse").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let extra_recursions = 1024; - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); - - // takes the number of recursions - // returns the number of left over recursions - assert_eq!( - u32::from_le_bytes( - builder::bare_call(addr) - .data((limits::CALL_STACK_DEPTH + extra_recursions).encode()) - .build_and_unwrap_result() - .data - .try_into() - .unwrap() - ), - // + 1 because when the call depth is reached the caller contract is trapped without - // the ability to return any data. hence the last call frame is untracked. - extra_recursions + 1, - ); - }); -} - -#[test] -fn gas_consumed_is_linear_for_nested_calls() { - let (code, _code_hash) = compile_module("recurse").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let [gas_0, gas_1, gas_2, gas_max] = { - [0u32, 1u32, 2u32, limits::CALL_STACK_DEPTH] - .iter() - .map(|i| { - let result = builder::bare_call(addr).data(i.encode()).build(); - assert_eq!( - u32::from_le_bytes(result.result.unwrap().data.try_into().unwrap()), - 0 - ); - result.gas_consumed - }) - .collect::>() - .try_into() - .unwrap() - }; - - let gas_per_recursion = gas_2.checked_sub(&gas_1).unwrap(); - assert_eq!(gas_max, gas_0 + gas_per_recursion * limits::CALL_STACK_DEPTH as u64); - }); -} - -#[test] -fn read_only_call_cannot_store() { - let (binary_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - // Read-only call fails when modifying storage. - assert_err_ignore_postinfo!( - builder::call(addr_caller).data((&addr_callee, 100u32).encode()).build(), - >::ContractTrapped - ); - }); -} - -#[test] -fn read_only_call_cannot_transfer() { - let (binary_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - // Read-only call fails when a non-zero value is set. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data( - (addr_callee, pallet_revive_uapi::CallFlags::READ_ONLY.bits(), 100u64).encode() - ) - .build(), - >::StateChangeDenied - ); - }); -} - -#[test] -fn read_only_subsequent_call_cannot_store() { - let (binary_read_only_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (binary_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_read_only_caller)) - .build_and_unwrap_contract(); - let Contract { addr: addr_subsequent_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - // Subsequent call input. - let input = (&addr_callee, pallet_revive_uapi::CallFlags::empty().bits(), 0u64, 100u32); - - // Read-only call fails when modifying storage. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((&addr_subsequent_caller, input).encode()) - .build(), - >::ContractTrapped - ); - }); -} - -#[test] -fn read_only_call_works() { - let (binary_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - assert_ok!(builder::call(addr_caller).data(addr_callee.encode()).build()); - }); -} - -#[test] -fn create1_with_value_works() { - let (code, code_hash) = compile_module("create1_with_value").unwrap(); - let value = 42; - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create the contract: Constructor does nothing. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: Deploys itself using create1 and the expected value - assert_ok!(builder::call(addr).value(value).data(code_hash.encode()).build()); - - // We should see the expected balance at the expected account - let address = crate::address::create1(&addr, 1); - let account_id = ::AddressMapper::to_account_id(&address); - let usable_balance = ::Currency::usable_balance(&account_id); - assert_eq!(usable_balance, value); - }); -} - -#[test] -fn gas_price_api_works() { - let (code, _) = compile_module("gas_price").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It echoes back the value returned by the gas price API. - let received = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(u64::from_le_bytes(received.data[..].try_into().unwrap()), u64::from(GAS_PRICE)); - }); -} - -#[test] -fn base_fee_api_works() { - let (code, _) = compile_module("base_fee").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It echoes back the value returned by the base fee API. - let received = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(received.data[..].try_into().unwrap()), U256::zero()); - }); -} - -#[test] -fn call_data_size_api_works() { - let (code, _) = compile_module("call_data_size").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It echoes back the value returned by the call data size API. - let received = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 0); - - let received = builder::bare_call(addr).data(vec![1; 256]).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 256); - }); -} - -#[test] -fn call_data_copy_api_works() { - let (code, _) = compile_module("call_data_copy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call fixture: Expects an input of [255; 32] and executes tests. - assert_ok!(builder::call(addr).data(vec![255; 32]).build()); - }); -} - -#[test] -fn static_data_limit_is_enforced() { - let (oom_rw_trailing, _) = compile_module("oom_rw_trailing").unwrap(); - let (oom_rw_included, _) = compile_module("oom_rw_included").unwrap(); - let (oom_ro, _) = compile_module("oom_ro").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - oom_rw_trailing, - deposit_limit::(), - ), - >::StaticMemoryTooLarge - ); - - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - oom_rw_included, - deposit_limit::(), - ), - >::BlobTooLarge - ); - - assert_err!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), oom_ro, deposit_limit::(),), - >::BlobTooLarge - ); - }); -} - -#[test] -fn call_diverging_out_len_works() { - let (code, _) = compile_module("call_diverging_out_len").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create the contract: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It will issue calls and deploys, asserting on - // correct output if the supplied output length was smaller than - // than what the callee returned. - assert_ok!(builder::call(addr).build()); - }); -} - -#[test] -fn chain_id_works() { - let (code, _) = compile_module("chain_id").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let chain_id = U256::from(::ChainId::get()); - let received = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_result(); - assert_eq!(received.result.data, chain_id.encode()); - }); -} - -#[test] -fn call_data_load_api_works() { - let (code, _) = compile_module("call_data_load").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It reads a byte for the offset and then returns - // what call data load returned using this byte as the offset. - let input = (3u8, U256::max_value(), U256::max_value()).encode(); - let received = builder::bare_call(addr).data(input).build().result.unwrap(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(&received.data), U256::max_value()); - - // Edge case - let input = (2u8, U256::from(255).to_big_endian()).encode(); - let received = builder::bare_call(addr).data(input).build().result.unwrap(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(&received.data), U256::from(65280)); - - // Edge case - let received = builder::bare_call(addr).data(vec![1]).build().result.unwrap(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(&received.data), U256::zero()); - - // OOB case - let input = (42u8).encode(); - let received = builder::bare_call(addr).data(input).build().result.unwrap(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(&received.data), U256::zero()); - - // No calldata should return the zero value - let received = builder::bare_call(addr).build().result.unwrap(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!(U256::from_little_endian(&received.data), U256::zero()); - }); -} - -#[test] -fn return_data_api_works() { - let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); - let (code_return_with_data, hash_return_with_data) = - compile_module("return_with_data").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Upload the io echoing fixture for later use - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - code_return_with_data, - deposit_limit::(), - )); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code_return_data_api)) - .build_and_unwrap_contract(); - - // Call the contract: It will issue calls and deploys, asserting on - assert_ok!(builder::call(addr) - .value(10 * 1024) - .data(hash_return_with_data.encode()) - .build()); - }); -} - -#[test] -fn immutable_data_works() { - let (code, _) = compile_module("immutable_data").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let data = [0xfe; 8]; - - // Create fixture: Constructor sets the immtuable data - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .data(data.to_vec()) - .build_and_unwrap_contract(); - - let contract = test_utils::get_contract(&addr); - let account = ::AddressMapper::to_account_id(&addr); - let actual_deposit = - test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account); - - assert_eq!(contract.immutable_data_len(), data.len() as u32); - - // Storing immmutable data charges storage deposit; verify it explicitly. - assert_eq!(actual_deposit, test_utils::contract_base_deposit(&addr)); - - // make sure it is also recorded in the base deposit - assert_eq!( - test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account), - contract.storage_base_deposit(), - ); - - // Call the contract: Asserts the input to equal the immutable data - assert_ok!(builder::call(addr).data(data.to_vec()).build()); - }); -} - -#[test] -fn sbrk_cannot_be_deployed() { - let (code, _) = compile_module("sbrk").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - code.clone(), - deposit_limit::(), - ), - >::InvalidInstruction - ); - - assert_err!( - builder::bare_instantiate(Code::Upload(code)).build().result, - >::InvalidInstruction - ); - }); -} - -#[test] -fn overweight_basic_block_cannot_be_deployed() { - let (code, _) = compile_module("basic_block").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - code.clone(), - deposit_limit::(), - ), - >::BasicBlockTooLarge - ); - - assert_err!( - builder::bare_instantiate(Code::Upload(code)).build().result, - >::BasicBlockTooLarge - ); - }); -} - -#[test] -fn origin_api_works() { - let (code, _) = compile_module("origin").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: Asserts the origin API to work as expected - assert_ok!(builder::call(addr).build()); - }); -} - -#[test] -fn code_hash_works() { - use crate::precompiles::{Precompile, EVM_REVERT}; - use precompiles::NoInfo; - - let builtin_precompile = H160(NoInfo::::MATCHER.base_address()); - let primitive_precompile = H160::from_low_u64_be(1); - - let (code_hash_code, self_code_hash) = compile_module("code_hash").unwrap(); - let (dummy_code, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code_hash_code)).build_and_unwrap_contract(); - let Contract { addr: dummy_addr, .. } = - builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); - - // code hash of dummy contract - assert_ok!(builder::call(addr).data((dummy_addr, code_hash).encode()).build()); - // code hash of itself - assert_ok!(builder::call(addr).data((addr, self_code_hash).encode()).build()); - // code hash of primitive pre-compile (exist but have no bytecode) - assert_ok!(builder::call(addr) - .data((primitive_precompile, crate::exec::EMPTY_CODE_HASH).encode()) - .build()); - // code hash of normal pre-compile (do have a bytecode) - assert_ok!(builder::call(addr) - .data((builtin_precompile, sp_io::hashing::keccak_256(&EVM_REVERT)).encode()) - .build()); - - // EOA doesn't exists - assert_err!( - builder::bare_call(addr) - .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) - .build() - .result, - Error::::ContractTrapped - ); - // non-existing will return zero - assert_ok!(builder::call(addr).data((BOB_ADDR, H256::zero()).encode()).build()); - - // create EOA - let _ = ::Currency::set_balance( - &::AddressMapper::to_account_id(&BOB_ADDR), - 1_000_000, - ); - - // EOA returns empty code hash - assert_ok!(builder::call(addr) - .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) - .build()); - }); -} - -#[test] -fn code_size_works() { - let (tester_code, _) = compile_module("extcodesize").unwrap(); - let tester_code_len = tester_code.len() as u64; - - let (dummy_code, _) = compile_module("dummy").unwrap(); - let dummy_code_len = dummy_code.len() as u64; - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr: tester_addr, .. } = - builder::bare_instantiate(Code::Upload(tester_code)).build_and_unwrap_contract(); - let Contract { addr: dummy_addr, .. } = - builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); - - // code size of another contract address - assert_ok!(builder::call(tester_addr).data((dummy_addr, dummy_code_len).encode()).build()); - - // code size of own contract address - assert_ok!(builder::call(tester_addr) - .data((tester_addr, tester_code_len).encode()) - .build()); - - // code size of non contract accounts - assert_ok!(builder::call(tester_addr).data(([8u8; 20], 0u64).encode()).build()); - }); -} - -#[test] -fn origin_must_be_mapped() { - let (code, hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - ::Currency::set_balance(&EVE, 1_000_000); - - let eve = RuntimeOrigin::signed(EVE); - - // alice can instantiate as she doesn't need a mapping - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // without a mapping eve can neither call nor instantiate - assert_err!( - builder::bare_call(addr).origin(eve.clone()).build().result, - >::AccountUnmapped - ); - assert_err!( - builder::bare_instantiate(Code::Existing(hash)) - .origin(eve.clone()) - .build() - .result, - >::AccountUnmapped - ); - - // after mapping eve is usable as an origin - >::map_account(eve.clone()).unwrap(); - assert_ok!(builder::bare_call(addr).origin(eve.clone()).build().result); - assert_ok!(builder::bare_instantiate(Code::Existing(hash)).origin(eve).build().result); - }); -} - -#[test] -fn mapped_address_works() { - let (code, _) = compile_module("terminate_and_send_to_argument").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - - // without a mapping everything will be send to the fallback account - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract(); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); - builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); - - // after mapping it will be sent to the real eve account - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - // need some balance to pay for the map deposit - ::Currency::set_balance(&EVE, 1_000); - >::map_account(RuntimeOrigin::signed(EVE)).unwrap(); - builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); - assert_eq!(::Currency::total_balance(&EVE), 1_100); - }); -} - -#[test] -fn recovery_works() { - let (code, _) = compile_module("terminate_and_send_to_argument").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - - // eve puts her AccountId20 as argument to terminate but forgot to register - // her AccountId32 first so now the funds are trapped in her fallback account - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract(); - assert_eq!(::Currency::total_balance(&EVE), 0); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); - builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); - assert_eq!(::Currency::total_balance(&EVE), 0); - - let call = RuntimeCall::Balances(pallet_balances::Call::transfer_all { - dest: EVE, - keep_alive: false, - }); - - // she now uses the recovery function to move all funds from the fallback - // account to her real account - >::dispatch_as_fallback_account(RuntimeOrigin::signed(EVE), Box::new(call)) - .unwrap(); - assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); - assert_eq!(::Currency::total_balance(&EVE), 100); - }); -} - -#[test] -fn skip_transfer_works() { - let (code_caller, _) = compile_module("call").unwrap(); - let (code, _) = compile_module("store_call").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - ::Currency::set_balance(&BOB, 0); - - // when gas is some (transfers enabled): bob has no money: fail - assert_err!( - Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - input: code.clone().into(), - gas: Some(1u32.into()), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - ), - EthTransactError::Message(format!( - "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" - )) - ); - - // no gas specified (all transfers are skipped): even without money bob can deploy - assert_ok!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - input: code.clone().into(), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - )); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let Contract { addr: caller_addr, .. } = - builder::bare_instantiate(Code::Upload(code_caller)).build_and_unwrap_contract(); - - // call directly: fails with enabled transfers - assert_err!( - Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(addr), - input: 0u32.encode().into(), - gas: Some(1u32.into()), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - ), - EthTransactError::Message(format!( - "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" - )) - ); - - // fails to call through other contract - // we didn't roll back the storage changes done by the previous - // call. So the item already exists. We simply increase the size of - // the storage item to incur some deposits (which bob can't pay). - assert!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(caller_addr), - input: (1u32, &addr).encode().into(), - gas: Some(1u32.into()), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - ) - .is_err(),); - - // works when no gas is specified (skip transfer) - assert_ok!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(addr), - input: 2u32.encode().into(), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - )); - - // call through contract works when transfers are skipped - assert_ok!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(caller_addr), - input: (3u32, &addr).encode().into(), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - )); - - // works with transfers enabled if we don't incur a storage cost - // we shrink the item so its actually a refund - assert_ok!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(caller_addr), - input: (2u32, &addr).encode().into(), - gas: Some(1u32.into()), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - )); - - // fails when trying to increase the storage item size - assert!(Pallet::::dry_run_eth_transact( - GenericTransaction { - from: Some(BOB_ADDR), - to: Some(caller_addr), - input: (3u32, &addr).encode().into(), - gas: Some(1u32.into()), - ..Default::default() - }, - Weight::MAX, - |_, _| 0u64, - ) - .is_err()); - }); -} - -#[test] -fn gas_limit_api_works() { - let (code, _) = compile_module("gas_limit").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - // Call the contract: It echoes back the value returned by the gas limit API. - let received = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(received.flags, ReturnFlags::empty()); - assert_eq!( - u64::from_le_bytes(received.data[..].try_into().unwrap()), - ::BlockWeights::get().max_block.ref_time() - ); - }); -} - -#[test] -fn unknown_syscall_rejected() { - let (code, _) = compile_module("unknown_syscall").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - - assert_err!( - builder::bare_instantiate(Code::Upload(code)).build().result, - >::CodeRejected, - ) - }); -} - -#[test] -fn unstable_interface_rejected() { - let (code, _) = compile_module("unstable_interface").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - ::Currency::set_balance(&ALICE, 1_000_000); - - Test::set_unstable_interface(false); - assert_err!( - builder::bare_instantiate(Code::Upload(code.clone())).build().result, - >::CodeRejected, - ); - - Test::set_unstable_interface(true); - assert_ok!(builder::bare_instantiate(Code::Upload(code)).build().result); - }); -} - -#[test] -fn tracing_works_for_transfers() { - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000); - let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); - trace(&mut tracer, || { - builder::bare_call(BOB_ADDR).evm_value(10.into()).build_and_unwrap_result(); - }); - - let trace = tracer.collect_trace(); - assert_eq!( - trace, - Some(CallTrace { - from: ALICE_ADDR, - to: BOB_ADDR, - value: Some(U256::from(10)), - call_type: CallType::Call, - ..Default::default() - }) - ) - }); -} - -#[test] -fn call_tracing_works() { - use crate::evm::*; - use CallType::*; - let (code, _code_hash) = compile_module("tracing").unwrap(); - let (binary_callee, _) = compile_module("tracing_callee").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000); - - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).evm_value(10_000_000.into()).build_and_unwrap_contract(); - - - let tracer_configs = vec![ - CallTracerConfig{ with_logs: false, only_top_call: false}, - CallTracerConfig{ with_logs: false, only_top_call: false}, - CallTracerConfig{ with_logs: false, only_top_call: true}, - ]; - - // Verify that the first trace report the same weight reported by bare_call - // TODO: fix tracing ( https://github.com/paritytech/polkadot-sdk/issues/8362 ) - /* - let mut tracer = CallTracer::new(false, |w| w); - let gas_used = trace(&mut tracer, || { - builder::bare_call(addr).data((3u32, addr_callee).encode()).build().gas_consumed - }); - let trace = tracer.collect_trace().unwrap(); - assert_eq!(&trace.gas_used, &gas_used); - */ - - // Discarding gas usage, check that traces reported are correct - for config in tracer_configs { - let logs = if config.with_logs { - vec![ - CallLog { - address: addr, - topics: Default::default(), - data: b"before".to_vec().into(), - position: 0, - }, - CallLog { - address: addr, - topics: Default::default(), - data: b"after".to_vec().into(), - position: 1, - }, - ] - } else { - vec![] - }; - - let calls = if config.only_top_call { - vec![] - } else { - vec![ - CallTrace { - from: addr, - to: addr_callee, - input: 2u32.encode().into(), - output: hex_literal::hex!( - "08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a546869732066756e6374696f6e20616c77617973206661696c73000000000000" - ).to_vec().into(), - revert_reason: Some("revert: This function always fails".to_string()), - error: Some("execution reverted".to_string()), - call_type: Call, - value: Some(U256::from(0)), - ..Default::default() - }, - CallTrace { - from: addr, - to: addr, - input: (2u32, addr_callee).encode().into(), - call_type: Call, - logs: logs.clone(), - value: Some(U256::from(0)), - calls: vec![ - CallTrace { - from: addr, - to: addr_callee, - input: 1u32.encode().into(), - output: Default::default(), - error: Some("ContractTrapped".to_string()), - call_type: Call, - value: Some(U256::from(0)), - ..Default::default() - }, - CallTrace { - from: addr, - to: addr, - input: (1u32, addr_callee).encode().into(), - call_type: Call, - logs: logs.clone(), - value: Some(U256::from(0)), - calls: vec![ - CallTrace { - from: addr, - to: addr_callee, - input: 0u32.encode().into(), - output: 0u32.to_le_bytes().to_vec().into(), - call_type: Call, - value: Some(U256::from(0)), - ..Default::default() - }, - CallTrace { - from: addr, - to: addr, - input: (0u32, addr_callee).encode().into(), - call_type: Call, - value: Some(U256::from(0)), - calls: vec![ - CallTrace { - from: addr, - to: BOB_ADDR, - value: Some(U256::from(100)), - call_type: CallType::Call, - ..Default::default() - } - ], - ..Default::default() - }, - ], - ..Default::default() - }, - ], - ..Default::default() - }, - ] - }; - - let mut tracer = CallTracer::new(config, |_| U256::zero()); - trace(&mut tracer, || { - builder::bare_call(addr).data((3u32, addr_callee).encode()).build() - }); - - let trace = tracer.collect_trace(); - let expected_trace = CallTrace { - from: ALICE_ADDR, - to: addr, - input: (3u32, addr_callee).encode().into(), - call_type: Call, - logs: logs.clone(), - value: Some(U256::from(0)), - calls: calls, - ..Default::default() - }; - - assert_eq!( - trace, - expected_trace.into(), - ); - } - }); -} - -#[test] -fn create_call_tracing_works() { - use crate::evm::*; - let (code, code_hash) = compile_module("create2_with_value").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000); - - let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); - - let Contract { addr, .. } = trace(&mut tracer, || { - builder::bare_instantiate(Code::Upload(code.clone())) - .evm_value(100.into()) - .salt(None) - .build_and_unwrap_contract() - }); - - let call_trace = tracer.collect_trace().unwrap(); - assert_eq!( - call_trace, - CallTrace { - from: ALICE_ADDR, - to: addr, - value: Some(100.into()), - input: Bytes(code.clone()), - call_type: CallType::Create, - ..Default::default() - } - ); - - let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); - let data = b"garbage"; - let input = (code_hash, data).encode(); - trace(&mut tracer, || { - assert_ok!(builder::call(addr).data(input.clone()).build()); - }); - - let call_trace = tracer.collect_trace().unwrap(); - let child_addr = crate::address::create2(&addr, &code, data, &[1u8; 32]); - - assert_eq!( - call_trace, - CallTrace { - from: ALICE_ADDR, - to: addr, - value: Some(0.into()), - input: input.clone().into(), - calls: vec![CallTrace { - from: addr, - input: input.clone().into(), - to: child_addr, - value: Some(0.into()), - call_type: CallType::Create2, - ..Default::default() - },], - ..Default::default() - } - ); - }); -} - -#[test] -fn prestate_tracing_works() { - use crate::evm::*; - use alloc::collections::BTreeMap; - - let (dummy_code, _) = compile_module("dummy").unwrap(); - let (code, _) = compile_module("tracing").unwrap(); - let (callee_code, _) = compile_module("tracing_callee").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000); - - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(callee_code.clone())) - .build_and_unwrap_contract(); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) - .native_value(10) - .build_and_unwrap_contract(); - - // redact balance so that tests are resilient to weight changes - let alice_redacted_balance = Some(U256::from(1)); - - let test_cases: Vec<(Box, _, _)> = vec![ - ( - Box::new(|| { - builder::bare_call(addr) - .data((3u32, addr_callee).encode()) - .build_and_unwrap_result(); - }), - PrestateTracerConfig { - diff_mode: false, - disable_storage: false, - disable_code: false, - }, - PrestateTrace::Prestate(BTreeMap::from([ - ( - ALICE_ADDR, - PrestateTraceInfo { - balance: alice_redacted_balance, - nonce: Some(2), - ..Default::default() - }, - ), - ( - BOB_ADDR, - PrestateTraceInfo { balance: Some(U256::from(0u64)), ..Default::default() }, - ), - ( - addr_callee, - PrestateTraceInfo { - balance: Some(U256::from(0u64)), - code: Some(Bytes(callee_code.clone())), - nonce: Some(1), - ..Default::default() - }, - ), - ( - addr, - PrestateTraceInfo { - balance: Some(U256::from(10_000_000u64)), - code: Some(Bytes(code.clone())), - nonce: Some(1), - ..Default::default() - }, - ), - ])), - ), - ( - Box::new(|| { - builder::bare_call(addr) - .data((3u32, addr_callee).encode()) - .build_and_unwrap_result(); - }), - PrestateTracerConfig { - diff_mode: true, - disable_storage: false, - disable_code: false, - }, - PrestateTrace::DiffMode { - pre: BTreeMap::from([ - ( - BOB_ADDR, - PrestateTraceInfo { - balance: Some(U256::from(100u64)), - ..Default::default() - }, - ), - ( - addr, - PrestateTraceInfo { - balance: Some(U256::from(9_999_900u64)), - code: Some(Bytes(code.clone())), - nonce: Some(1), - ..Default::default() - }, - ), - ]), - post: BTreeMap::from([ - ( - BOB_ADDR, - PrestateTraceInfo { - balance: Some(U256::from(200u64)), - ..Default::default() - }, - ), - ( - addr, - PrestateTraceInfo { - balance: Some(U256::from(9_999_800u64)), - ..Default::default() - }, - ), - ]), - }, - ), - ( - Box::new(|| { - builder::bare_instantiate(Code::Upload(dummy_code.clone())) - .salt(None) - .build_and_unwrap_result(); - }), - PrestateTracerConfig { - diff_mode: true, - disable_storage: false, - disable_code: false, - }, - PrestateTrace::DiffMode { - pre: BTreeMap::from([( - ALICE_ADDR, - PrestateTraceInfo { - balance: alice_redacted_balance, - nonce: Some(2), - ..Default::default() - }, - )]), - post: BTreeMap::from([ - ( - ALICE_ADDR, - PrestateTraceInfo { - balance: alice_redacted_balance, - nonce: Some(3), - ..Default::default() - }, - ), - ( - create1(&ALICE_ADDR, 1), - PrestateTraceInfo { - code: Some(dummy_code.clone().into()), - balance: Some(U256::from(0)), - nonce: Some(1), - ..Default::default() - }, - ), - ]), - }, - ), - ]; - - for (exec_call, config, expected_trace) in test_cases.into_iter() { - let mut tracer = PrestateTracer::::new(config); - trace(&mut tracer, || { - exec_call(); - }); - - let mut trace = tracer.collect_trace(); - - // redact alice balance - match trace { - PrestateTrace::DiffMode { ref mut pre, ref mut post } => { - pre.get_mut(&ALICE_ADDR).map(|info| { - info.balance = alice_redacted_balance; - }); - post.get_mut(&ALICE_ADDR).map(|info| { - info.balance = alice_redacted_balance; - }); - }, - PrestateTrace::Prestate(ref mut pre) => { - pre.get_mut(&ALICE_ADDR).map(|info| { - info.balance = alice_redacted_balance; - }); - }, - } - - assert_eq!(trace, expected_trace); - } - }); -} - -#[test] -fn unknown_precompiles_revert() { - let (code, _code_hash) = compile_module("read_only_call").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let cases: Vec<(H160, Box)> = vec![( - H160::from_low_u64_be(0x0a), - Box::new(|result| { - assert_err!(result, >::UnsupportedPrecompileAddress); - }), - )]; - - for (callee_addr, assert_result) in cases { - let result = - builder::bare_call(addr).data((callee_addr, [0u8; 0]).encode()).build().result; - assert_result(result); - } - }); -} - -#[test] -fn pure_precompile_works() { - use hex_literal::hex; - - let cases = vec![ - ( - "ECRecover", - H160::from_low_u64_be(1), - hex!("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").to_vec(), - hex!("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").to_vec(), - ), - ( - "Sha256", - H160::from_low_u64_be(2), - hex!("ec07171c4f0f0e2b").to_vec(), - hex!("d0591ea667763c69a5f5a3bae657368ea63318b2c9c8349cccaf507e3cbd7c7a").to_vec(), - ), - ( - "Ripemd160", - H160::from_low_u64_be(3), - hex!("ec07171c4f0f0e2b").to_vec(), - hex!("000000000000000000000000a9c5ebaf7589fd8acfd542c3a008956de84fbeb7").to_vec(), - ), - ( - "Identity", - H160::from_low_u64_be(4), - [42u8; 128].to_vec(), - [42u8; 128].to_vec(), - ), - ( - "Modexp", - H160::from_low_u64_be(5), - hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f").to_vec(), - hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec(), - ), - ( - "Bn128Add", - H160::from_low_u64_be(6), - hex!("18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7").to_vec(), - hex!("2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915").to_vec(), - ), - ( - "Bn128Mul", - H160::from_low_u64_be(7), - hex!("2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2").to_vec(), - hex!("070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc").to_vec(), - ), - ( - "Bn128Pairing", - H160::from_low_u64_be(8), - hex!("1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").to_vec(), - hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec(), - ), - ( - "Blake2F", - H160::from_low_u64_be(9), - hex!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001").to_vec(), - hex!("08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b").to_vec(), - ), - ]; - - for (description, precompile_addr, input, output) in cases { - let (code, _code_hash) = compile_module("call_and_return").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(1_000) - .build_and_unwrap_contract(); - - let result = builder::bare_call(addr) - .data( - (&precompile_addr, 100u64) - .encode() - .into_iter() - .chain(input) - .collect::>(), - ) - .build_and_unwrap_result(); - - assert_eq!( - Pallet::::evm_balance(&precompile_addr), - U256::from(100), - "{description}: unexpected balance" - ); - assert_eq!( - alloy_core::hex::encode(result.data), - alloy_core::hex::encode(output), - "{description} Unexpected output for precompile: {precompile_addr:?}", - ); - assert_eq!(result.flags, ReturnFlags::empty()); - }); - } -} - -#[test] -fn precompiles_work() { - use crate::precompiles::Precompile; - use alloy_core::sol_types::{Panic, PanicKind, Revert, SolError, SolInterface, SolValue}; - use precompiles::{INoInfo, NoInfo}; - - let precompile_addr = H160(NoInfo::::MATCHER.base_address()); - - let cases = vec![ - ( - INoInfo::INoInfoCalls::identity(INoInfo::identityCall { number: 42u64.into() }) - .abi_encode(), - 42u64.abi_encode(), - RuntimeReturnCode::Success, - ), - ( - INoInfo::INoInfoCalls::reverts(INoInfo::revertsCall { error: "panic".to_string() }) - .abi_encode(), - Revert::from("panic").abi_encode(), - RuntimeReturnCode::CalleeReverted, - ), - ( - INoInfo::INoInfoCalls::panics(INoInfo::panicsCall {}).abi_encode(), - Panic::from(PanicKind::Assert).abi_encode(), - RuntimeReturnCode::CalleeReverted, - ), - ( - INoInfo::INoInfoCalls::errors(INoInfo::errorsCall {}).abi_encode(), - Vec::new(), - RuntimeReturnCode::CalleeTrapped, - ), - // passing non decodeable input reverts with solidity panic - ( - b"invalid".to_vec(), - Panic::from(PanicKind::ResourceError).abi_encode(), - RuntimeReturnCode::CalleeReverted, - ), - ( - INoInfo::INoInfoCalls::passData(INoInfo::passDataCall { - inputLen: limits::CALLDATA_BYTES, - }) - .abi_encode(), - Vec::new(), - RuntimeReturnCode::Success, - ), - ( - INoInfo::INoInfoCalls::passData(INoInfo::passDataCall { - inputLen: limits::CALLDATA_BYTES + 1, - }) - .abi_encode(), - Vec::new(), - RuntimeReturnCode::CalleeTrapped, - ), - ( - INoInfo::INoInfoCalls::returnData(INoInfo::returnDataCall { - returnLen: limits::CALLDATA_BYTES - 4, - }) - .abi_encode(), - vec![42u8; limits::CALLDATA_BYTES as usize - 4], - RuntimeReturnCode::Success, - ), - ( - INoInfo::INoInfoCalls::returnData(INoInfo::returnDataCall { - returnLen: limits::CALLDATA_BYTES + 1, - }) - .abi_encode(), - vec![], - RuntimeReturnCode::CalleeTrapped, - ), - ]; - - for (input, output, error_code) in cases { - let (code, _code_hash) = compile_module("call_and_returncode").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let id = ::AddressMapper::to_account_id(&precompile_addr); - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(1000) - .build_and_unwrap_contract(); - - let result = builder::bare_call(addr) - .data( - (&precompile_addr, 0u64).encode().into_iter().chain(input).collect::>(), - ) - .build_and_unwrap_result(); - - // no account or contract info should be created for a NoInfo pre-compile - assert!(test_utils::get_contract_checked(&precompile_addr).is_none()); - assert!(!System::account_exists(&id)); - assert_eq!(Pallet::::evm_balance(&precompile_addr), U256::zero()); - - assert_eq!(result.flags, ReturnFlags::empty()); - assert_eq!(u32::from_le_bytes(result.data[..4].try_into().unwrap()), error_code as u32); - assert_eq!( - &result.data[4..], - &output, - "Unexpected output for precompile: {precompile_addr:?}", - ); - }); - } -} - -#[test] -fn precompiles_with_info_creates_contract() { - use crate::precompiles::Precompile; - use alloy_core::sol_types::SolInterface; - use precompiles::{IWithInfo, WithInfo}; - - let precompile_addr = H160(WithInfo::::MATCHER.base_address()); - - let cases = vec![( - IWithInfo::IWithInfoCalls::dummy(IWithInfo::dummyCall {}).abi_encode(), - Vec::::new(), - RuntimeReturnCode::Success, - )]; - - for (input, output, error_code) in cases { - let (code, _code_hash) = compile_module("call_and_returncode").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let id = ::AddressMapper::to_account_id(&precompile_addr); - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(1000) - .build_and_unwrap_contract(); - - let result = builder::bare_call(addr) - .data( - (&precompile_addr, 0u64).encode().into_iter().chain(input).collect::>(), - ) - .build_and_unwrap_result(); - - // a pre-compile with contract info should create an account on first call - assert!(test_utils::get_contract_checked(&precompile_addr).is_some()); - assert!(System::account_exists(&id)); - assert_eq!(Pallet::::evm_balance(&precompile_addr), U256::from(0)); - - assert_eq!(result.flags, ReturnFlags::empty()); - assert_eq!(u32::from_le_bytes(result.data[..4].try_into().unwrap()), error_code as u32); - assert_eq!( - &result.data[4..], - &output, - "Unexpected output for precompile: {precompile_addr:?}", - ); - }); - } -} - -#[test] -fn bump_nonce_once_works() { - let (code, hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - frame_system::Account::::mutate(&ALICE, |account| account.nonce = 1); - - let _ = ::Currency::set_balance(&BOB, 1_000_000); - frame_system::Account::::mutate(&BOB, |account| account.nonce = 1); - - builder::bare_instantiate(Code::Upload(code.clone())) - .origin(RuntimeOrigin::signed(ALICE)) - .bump_nonce(BumpNonce::Yes) - .salt(None) - .build_and_unwrap_result(); - assert_eq!(System::account_nonce(&ALICE), 2); - - // instantiate again is ok - let result = builder::bare_instantiate(Code::Existing(hash)) - .origin(RuntimeOrigin::signed(ALICE)) - .bump_nonce(BumpNonce::Yes) - .salt(None) - .build() - .result; - assert!(result.is_ok()); - - builder::bare_instantiate(Code::Upload(code.clone())) - .origin(RuntimeOrigin::signed(BOB)) - .bump_nonce(BumpNonce::No) - .salt(None) - .build_and_unwrap_result(); - assert_eq!(System::account_nonce(&BOB), 1); - - // instantiate again should fail - let err = builder::bare_instantiate(Code::Upload(code)) - .origin(RuntimeOrigin::signed(BOB)) - .bump_nonce(BumpNonce::No) - .salt(None) - .build() - .result - .unwrap_err(); - - assert_eq!(err, >::DuplicateContract.into()); - }); -} - -#[test] -fn code_size_for_precompiles_works() { - use crate::precompiles::Precompile; - use precompiles::NoInfo; - - let builtin_precompile = H160(NoInfo::::MATCHER.base_address()); - let primitive_precompile = H160::from_low_u64_be(1); - - let (code, _code_hash) = compile_module("extcodesize").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .native_value(1000) - .build_and_unwrap_contract(); - - // the primitive pre-compiles return 0 code size on eth - builder::bare_call(addr) - .data((&primitive_precompile, 0u64).encode()) - .build_and_unwrap_result(); - - // other precompiles should return the minimal evm revert code - builder::bare_call(addr) - .data((&builtin_precompile, 5u64).encode()) - .build_and_unwrap_result(); - }); -} - -#[test] -fn call_data_limit_is_enforced_subcalls() { - let (code, _code_hash) = compile_module("call_with_input_size").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let cases: Vec<(u32, Box)> = vec![ - ( - 0_u32, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - 1_u32, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - limits::CALLDATA_BYTES, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - limits::CALLDATA_BYTES + 1, - Box::new(|result| { - assert_err!(result, >::CallDataTooLarge); - }), - ), - ]; - - for (callee_input_size, assert_result) in cases { - let result = builder::bare_call(addr).data(callee_input_size.encode()).build().result; - assert_result(result); - } - }); -} - -#[test] -fn call_data_limit_is_enforced_root_call() { - let (code, _code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let cases: Vec<(H160, u32, Box)> = vec![ - ( - addr, - 0_u32, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - addr, - 1_u32, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - addr, - limits::CALLDATA_BYTES, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - addr, - limits::CALLDATA_BYTES + 1, - Box::new(|result| { - assert_err!(result, >::CallDataTooLarge); - }), - ), - ( - // limit is not enforced when tx calls EOA - BOB_ADDR, - limits::CALLDATA_BYTES + 1, - Box::new(|result| { - assert_ok!(result); - }), - ), - ]; - - for (addr, callee_input_size, assert_result) in cases { - let result = builder::bare_call(addr) - .data(vec![42; callee_input_size as usize]) - .build() - .result; - assert_result(result); - } - }); -} - -#[test] -fn return_data_limit_is_enforced() { - let (code, _code_hash) = compile_module("return_sized").unwrap(); - - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let cases: Vec<(u32, Box)> = vec![ - ( - 1_u32, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - limits::CALLDATA_BYTES, - Box::new(|result| { - assert_ok!(result); - }), - ), - ( - limits::CALLDATA_BYTES + 1, - Box::new(|result| { - assert_err!(result, >::ReturnDataTooLarge); - }), - ), - ]; - - for (return_size, assert_result) in cases { - let result = builder::bare_call(addr).data(return_size.encode()).build().result; - assert_result(result); - } - }); -} diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs new file mode 100644 index 0000000000000..81aab74f72f2f --- /dev/null +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -0,0 +1,4892 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The pallet-revive PVM specific integration test suite. + +use super::{ + precompiles, + precompiles::{INoInfo, NoInfo}, +}; +use crate::{ + address::{create1, create2, AddressMapper}, + assert_refcount, assert_return_code, + evm::{runtime::GAS_PRICE, CallTrace, CallTracer, CallType, GenericTransaction}, + exec::Key, + limits, + storage::DeletionQueueManager, + test_utils::builder::Contract, + tests::{ + builder, initialize_block, test_utils::*, Balances, CodeHashLockupDepositPercent, + Contracts, DepositPerByte, DepositPerItem, ExtBuilder, InstantiateAccount, RuntimeCall, + RuntimeEvent, RuntimeOrigin, System, Test, UploadAccount, DEPOSIT_PER_BYTE, *, + }, + tracing::trace, + weights::WeightInfo, + AccountInfo, AccountInfoOf, BalanceWithDust, BumpNonce, Code, Config, ContractInfo, + DeletionQueueCounter, DepositLimit, Error, EthTransactError, HoldReason, Pallet, PristineCode, + StorageDeposit, H160, +}; +use assert_matches::assert_matches; +use codec::Encode; +use frame_support::{ + assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, + storage::child, + traits::{ + fungible::{BalancedHold, Inspect, Mutate, MutateHold}, + tokens::Preservation, + OnIdle, OnInitialize, + }, + weights::{Weight, WeightMeter}, +}; +use frame_system::{EventRecord, Phase}; +use pallet_revive_fixtures::compile_module; +use pallet_revive_uapi::{ReturnErrorCode as RuntimeReturnCode, ReturnFlags}; +use pretty_assertions::{assert_eq, assert_ne}; +use sp_core::{Get, U256}; +use sp_io::hashing::blake2_256; +use sp_runtime::{testing::H256, traits::Zero, AccountId32, DispatchError, TokenError}; + +#[test] +fn transfer_with_dust_works() { + struct TestCase { + description: &'static str, + from_balance: BalanceWithDust, + to_balance: BalanceWithDust, + amount: BalanceWithDust, + expected_from_balance: BalanceWithDust, + expected_to_balance: BalanceWithDust, + total_issuance_diff: i64, + } + + let plank: u32 = ::NativeToEthRatio::get(); + + let test_cases = vec![ + TestCase { + description: "without dust", + from_balance: BalanceWithDust::new_unchecked::(100, 0), + to_balance: BalanceWithDust::new_unchecked::(0, 0), + amount: BalanceWithDust::new_unchecked::(1, 0), + expected_from_balance: BalanceWithDust::new_unchecked::(99, 0), + expected_to_balance: BalanceWithDust::new_unchecked::(1, 0), + total_issuance_diff: 0, + }, + TestCase { + description: "with dust", + from_balance: BalanceWithDust::new_unchecked::(100, 0), + to_balance: BalanceWithDust::new_unchecked::(0, 0), + amount: BalanceWithDust::new_unchecked::(1, 10), + expected_from_balance: BalanceWithDust::new_unchecked::(98, plank - 10), + expected_to_balance: BalanceWithDust::new_unchecked::(1, 10), + total_issuance_diff: 1, + }, + TestCase { + description: "just dust", + from_balance: BalanceWithDust::new_unchecked::(100, 0), + to_balance: BalanceWithDust::new_unchecked::(0, 0), + amount: BalanceWithDust::new_unchecked::(0, 10), + expected_from_balance: BalanceWithDust::new_unchecked::(99, plank - 10), + expected_to_balance: BalanceWithDust::new_unchecked::(0, 10), + total_issuance_diff: 1, + }, + TestCase { + description: "with existing dust", + from_balance: BalanceWithDust::new_unchecked::(100, 5), + to_balance: BalanceWithDust::new_unchecked::(0, plank - 5), + amount: BalanceWithDust::new_unchecked::(1, 10), + expected_from_balance: BalanceWithDust::new_unchecked::(98, plank - 5), + expected_to_balance: BalanceWithDust::new_unchecked::(2, 5), + total_issuance_diff: 0, + }, + TestCase { + description: "with enough existing dust", + from_balance: BalanceWithDust::new_unchecked::(100, 10), + to_balance: BalanceWithDust::new_unchecked::(0, plank - 10), + amount: BalanceWithDust::new_unchecked::(1, 10), + expected_from_balance: BalanceWithDust::new_unchecked::(99, 0), + expected_to_balance: BalanceWithDust::new_unchecked::(2, 0), + total_issuance_diff: -1, + }, + TestCase { + description: "receiver dust less than 1 plank", + from_balance: BalanceWithDust::new_unchecked::(100, plank / 10), + to_balance: BalanceWithDust::new_unchecked::(0, plank / 2), + amount: BalanceWithDust::new_unchecked::(1, plank / 10 * 3), + expected_from_balance: BalanceWithDust::new_unchecked::(98, plank / 10 * 8), + expected_to_balance: BalanceWithDust::new_unchecked::(1, plank / 10 * 8), + total_issuance_diff: 1, + }, + ]; + + for TestCase { + description, + from_balance, + to_balance, + amount, + expected_from_balance, + expected_to_balance, + total_issuance_diff, + } in test_cases.into_iter() + { + ExtBuilder::default().build().execute_with(|| { + set_balance_with_dust(&ALICE_ADDR, from_balance); + set_balance_with_dust(&BOB_ADDR, to_balance); + + let total_issuance = ::Currency::total_issuance(); + let evm_value = Pallet::::convert_native_to_evm(amount); + + let (value, dust) = amount.deconstruct(); + assert_eq!(Pallet::::has_dust(evm_value), !dust.is_zero()); + assert_eq!(Pallet::::has_balance(evm_value), !value.is_zero()); + + let result = + builder::bare_call(BOB_ADDR).evm_value(evm_value).build_and_unwrap_result(); + assert_eq!(result, Default::default(), "{description} tx failed"); + + assert_eq!( + Pallet::::evm_balance(&ALICE_ADDR), + Pallet::::convert_native_to_evm(expected_from_balance), + "{description}: invalid from balance" + ); + + assert_eq!( + Pallet::::evm_balance(&BOB_ADDR), + Pallet::::convert_native_to_evm(expected_to_balance), + "{description}: invalid to balance" + ); + + assert_eq!( + total_issuance as i64 - total_issuance_diff, + ::Currency::total_issuance() as i64, + "{description}: total issuance should match" + ); + }); + } +} + +#[test] +fn eth_call_transfer_with_dust_works() { + let (binary, _) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + let balance = + Pallet::::convert_native_to_evm(BalanceWithDust::new_unchecked::(100, 10)); + assert_ok!(builder::eth_call(addr).value(balance).build()); + + assert_eq!(Pallet::::evm_balance(&addr), balance); + }); +} + +#[test] +fn contract_call_transfer_with_dust_works() { + let (binary_caller, _code_hash_caller) = compile_module("call_with_value").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)) + .native_value(200) + .build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + let balance = + Pallet::::convert_native_to_evm(BalanceWithDust::new_unchecked::(100, 10)); + assert_ok!(builder::call(addr_caller).data((balance, addr_callee).encode()).build()); + + assert_eq!(Pallet::::evm_balance(&addr_callee), balance); + }); +} + +#[test] +fn deposit_limit_enforced_on_plain_transfer() { + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 1_000_000); + + // sending balance to a new account should fail when the limit is lower than the ed + let result = builder::bare_call(CHARLIE_ADDR) + .native_value(1) + .storage_deposit_limit(190.into()) + .build(); + assert_err!(result.result, >::StorageDepositLimitExhausted); + assert_eq!(result.storage_deposit, StorageDeposit::Charge(0)); + assert_eq!(get_balance(&CHARLIE), 0); + + // works when the account is prefunded + let result = builder::bare_call(BOB_ADDR) + .native_value(1) + .storage_deposit_limit(0.into()) + .build(); + assert_ok!(result.result); + assert_eq!(result.storage_deposit, StorageDeposit::Charge(0)); + assert_eq!(get_balance(&BOB), 1_000_001); + + // also works allowing enough deposit + let result = builder::bare_call(CHARLIE_ADDR) + .native_value(1) + .storage_deposit_limit(200.into()) + .build(); + assert_ok!(result.result); + assert_eq!(result.storage_deposit, StorageDeposit::Charge(200)); + assert_eq!(get_balance(&CHARLIE), 201); + }); +} + +#[test] +fn instantiate_and_call_and_deposit_event() { + let (binary, code_hash) = compile_module("event_and_return_on_deploy").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let value = 100; + + // We determine the storage deposit limit after uploading because it depends on ALICEs + // free balance which is changed by uploading a module. + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary, + deposit_limit::(), + )); + + // Drop previous events + initialize_block(2); + + // Check at the end to get hash on error easily + let Contract { addr, account_id } = builder::bare_instantiate(Code::Existing(code_hash)) + .native_value(value) + .build_and_unwrap_contract(); + assert!(AccountInfoOf::::contains_key(&addr)); + + let hold_balance = contract_base_deposit(&addr); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: value, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { + contract: addr, + data: vec![1, 2, 3, 4], + topics: vec![H256::repeat_byte(42)], + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: account_id.clone(), + transferred: hold_balance, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn create1_address_from_extrinsic() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary.clone(), + deposit_limit::(), + )); + + assert_eq!(System::account_nonce(&ALICE), 0); + System::inc_account_nonce(&ALICE); + + for nonce in 1..3 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .salt(None) + .build_and_unwrap_contract(); + assert!(AccountInfoOf::::contains_key(&addr)); + assert_eq!( + addr, + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) + ); + } + assert_eq!(System::account_nonce(&ALICE), 3); + + for nonce in 3..6 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) + .salt(None) + .build_and_unwrap_contract(); + assert!(AccountInfoOf::::contains_key(&addr)); + assert_eq!( + addr, + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) + ); + } + assert_eq!(System::account_nonce(&ALICE), 6); + }); +} + +#[test] +fn deposit_event_max_value_limit() { + let (binary, _code_hash) = compile_module("event_size").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(30_000) + .build_and_unwrap_contract(); + + // Call contract with allowed storage value. + assert_ok!(builder::call(addr) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer, + .data(limits::PAYLOAD_BYTES.encode()) + .build()); + + // Call contract with too large a storage value. + assert_err_ignore_postinfo!( + builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), + Error::::ValueTooLarge, + ); + }); +} + +// Fail out of fuel (ref_time weight) in the engine. +#[test] +fn run_out_of_fuel_engine() { + let (binary, _code_hash) = compile_module("run_out_of_gas").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(100 * min_balance) + .build_and_unwrap_contract(); + + // Call the contract with a fixed gas limit. It must run out of gas because it just + // loops forever. + assert_err_ignore_postinfo!( + builder::call(addr) + .gas_limit(Weight::from_parts(10_000_000_000, u64::MAX)) + .build(), + Error::::OutOfGas, + ); + }); +} + +// Fail out of fuel (ref_time weight) in the host. +#[test] +fn run_out_of_fuel_host() { + use crate::precompiles::Precompile; + use alloy_core::sol_types::SolInterface; + + let precompile_addr = H160(NoInfo::::MATCHER.base_address()); + let input = INoInfo::INoInfoCalls::consumeMaxGas(INoInfo::consumeMaxGasCall {}).abi_encode(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let result = builder::bare_call(precompile_addr).data(input).build().result; + assert_err!(result, >::OutOfGas); + }); +} + +#[test] +fn gas_syncs_work() { + let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let contract = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let result = builder::bare_call(contract.addr).data(0u32.encode()).build(); + assert_ok!(result.result); + let engine_consumed_noop = result.gas_consumed.ref_time(); + + let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); + assert_ok!(result.result); + let gas_consumed_once = result.gas_consumed.ref_time(); + let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); + let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; + + let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); + assert_ok!(result.result); + let gas_consumed_twice = result.gas_consumed.ref_time(); + let host_consumed_twice = host_consumed_once * 2; + let engine_consumed_twice = gas_consumed_twice - host_consumed_twice - engine_consumed_noop; + + // Second contract just repeats first contract's instructions twice. + // If runtime syncs gas with the engine properly, this should pass. + assert_eq!(engine_consumed_twice, engine_consumed_once * 2); + }); +} + +/// Check that contracts with the same account id have different trie ids. +/// Check the `Nonce` storage item for more information. +#[test] +fn instantiate_unique_trie_id() { + let (binary, code_hash) = compile_module("self_destruct").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_limit::()) + .unwrap(); + + // Instantiate the contract and store its trie id for later comparison. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_contract(); + let trie_id = get_contract(&addr).trie_id; + + // Try to instantiate it again without termination should yield an error. + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).build(), + >::DuplicateContract, + ); + + // Terminate the contract. + assert_ok!(builder::call(addr).build()); + + // Re-Instantiate after termination. + assert_ok!(builder::instantiate(code_hash).build()); + + // Trie ids shouldn't match or we might have a collision + assert_ne!(trie_id, get_contract(&addr).trie_id); + }); +} + +#[test] +fn storage_work() { + let (code, _code_hash) = compile_module("storage").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + builder::bare_call(addr).build_and_unwrap_result(); + }); +} + +#[test] +fn storage_max_value_limit() { + let (binary, _code_hash) = compile_module("storage_size").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(30_000) + .build_and_unwrap_contract(); + get_contract(&addr); + + // Call contract with allowed storage value. + assert_ok!(builder::call(addr) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer + .data(limits::PAYLOAD_BYTES.encode()) + .build()); + + // Call contract with too large a storage value. + assert_err_ignore_postinfo!( + builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), + Error::::ValueTooLarge, + ); + }); +} + +#[test] +fn clear_storage_on_zero_value() { + let (code, _code_hash) = compile_module("clear_storage_on_zero_value").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + builder::bare_call(addr).build_and_unwrap_result(); + }); +} + +#[test] +fn transient_storage_work() { + let (code, _code_hash) = compile_module("transient_storage").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + builder::bare_call(addr).build_and_unwrap_result(); + }); +} + +#[test] +fn transient_storage_limit_in_call() { + let (binary_caller, _code_hash_caller) = + compile_module("create_transient_storage_and_call").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("set_transient_storage").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + // Call contracts with storage values within the limit. + // Caller and Callee contracts each set a transient storage value of size 100. + assert_ok!(builder::call(addr_caller) + .data((100u32, 100u32, &addr_callee).encode()) + .build(),); + + // Call a contract with a storage value that is too large. + // Limit exceeded in the caller contract. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((4u32 * 1024u32, 200u32, &addr_callee).encode()) + .build(), + >::OutOfTransientStorage, + ); + + // Call a contract with a storage value that is too large. + // Limit exceeded in the callee contract. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((50u32, 4 * 1024u32, &addr_callee).encode()) + .build(), + >::ContractTrapped + ); + }); +} + +#[test] +fn deploy_and_call_other_contract() { + let (caller_binary, _caller_code_hash) = compile_module("caller_contract").unwrap(); + let (callee_binary, callee_code_hash) = compile_module("return_with_data").unwrap(); + let code_load_weight = crate::vm::code_load_weight(callee_binary.len() as u32); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr: caller_addr, account_id: caller_account } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + let callee_addr = create2( + &caller_addr, + &callee_binary, + &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in binary + &[0u8; 32], + ); + let callee_account = ::AddressMapper::to_account_id(&callee_addr); + + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + callee_binary, + deposit_limit::(), + ) + .unwrap(); + + // Drop previous events + initialize_block(2); + + // Call BOB contract, which attempts to instantiate and call the callee contract and + // makes various assertions on the results from those calls. + assert_ok!(builder::call(caller_addr) + .data( + (callee_code_hash, code_load_weight.ref_time(), code_load_weight.proof_size()) + .encode() + ) + .build()); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: callee_account.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: callee_account.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: callee_account.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: caller_account.clone(), + to: callee_account.clone(), + amount: 32768 // hardcoded in binary + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: caller_account.clone(), + to: callee_account.clone(), + amount: 32768, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: callee_account.clone(), + transferred: 555, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn delegate_call() { + let (caller_binary, _caller_code_hash) = compile_module("delegate_call").unwrap(); + let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(300_000) + .build_and_unwrap_contract(); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, u64::MAX, u64::MAX).encode()) + .build()); + }); +} + +#[test] +fn delegate_call_non_existant_is_noop() { + let (caller_binary, _caller_code_hash) = compile_module("delegate_call_simple").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(300_000) + .build_and_unwrap_contract(); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((BOB_ADDR, u64::MAX, u64::MAX).encode()) + .build()); + + assert_eq!(get_balance(&BOB_FALLBACK), 0); + }); +} + +#[test] +fn delegate_call_with_weight_limit() { + let (caller_binary, _caller_code_hash) = compile_module("delegate_call").unwrap(); + let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(300_000) + .build_and_unwrap_contract(); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + // fails, not enough weight + assert_err!( + builder::bare_call(caller_addr) + .native_value(1337) + .data((callee_addr, 100u64, 100u64).encode()) + .build() + .result, + Error::::ContractTrapped, + ); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 500_000_000u64, 100_000u64).encode()) + .build()); + }); +} + +#[test] +fn delegate_call_with_deposit_limit() { + let (caller_binary, _caller_code_hash) = compile_module("delegate_call_deposit_limit").unwrap(); + let (callee_binary, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(300_000) + .build_and_unwrap_contract(); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + // Delegate call will write 1 storage and deposit of 2 (1 item) + 32 (bytes) is required. + // + 32 + 16 for blake2_128concat + // Fails, not enough deposit + let ret = builder::bare_call(caller_addr) + .native_value(1337) + .data((callee_addr, 81u64).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 82u64).encode()) + .build()); + }); +} + +#[test] +fn transfer_expendable_cannot_kill_account() { + let (binary, _code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(1_000) + .build_and_unwrap_contract(); + + // Check that the BOB contract has been instantiated. + get_contract(&addr); + + let account = ::AddressMapper::to_account_id(&addr); + let total_balance = ::Currency::total_balance(&account); + + assert_eq!( + get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account), + contract_base_deposit(&addr) + ); + + // Some or the total balance is held, so it can't be transferred. + assert_err!( + <::Currency as Mutate>::transfer( + &account, + &ALICE, + total_balance, + Preservation::Expendable, + ), + TokenError::FundsUnavailable, + ); + + assert_eq!(::Currency::total_balance(&account), total_balance); + }); +} + +#[test] +fn cannot_self_destruct_through_draining() { + let (binary, _code_hash) = compile_module("drain").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let value = 1_000; + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(value) + .build_and_unwrap_contract(); + let account = ::AddressMapper::to_account_id(&addr); + + // Check that the BOB contract has been instantiated. + get_contract(&addr); + + // Call BOB which makes it send all funds to the zero address + // The contract code asserts that the transfer fails with the correct error code + assert_ok!(builder::call(addr).build()); + + // Make sure the account wasn't remove by sending all free balance away. + assert_eq!( + ::Currency::total_balance(&account), + value + contract_base_deposit(&addr) + min_balance, + ); + }); +} + +#[test] +fn cannot_self_destruct_through_storage_refund_after_price_change() { + let (binary, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let contract = builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + let info_deposit = contract_base_deposit(&contract.addr); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit); + assert_eq!(get_contract(&contract.addr).extra_deposit(), 0); + assert_eq!( + ::Currency::total_balance(&contract.account_id), + info_deposit + min_balance + ); + + // Create 100 (16 + 32 bytes for key for blake128 concat) bytes of storage with a + // price of per byte and a single storage item of price 2 + assert_ok!(builder::call(contract.addr).data(100u32.to_le_bytes().to_vec()).build()); + assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit + 100 + 16 + 32 + 2); + + // Increase the byte price and trigger a refund. This should not have any influence + // because the removal is pro rata and exactly those 100 bytes should have been + // removed as we didn't delete the key. + DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); + assert_ok!(builder::call(contract.addr).data(0u32.to_le_bytes().to_vec()).build()); + + // Make sure the account wasn't removed by the refund + assert_eq!( + ::Currency::total_balance(&contract.account_id), + get_contract(&contract.addr).total_deposit() + min_balance, + ); + // + 1 because due to fixed point arithmetic we can sometimes refund + // one unit to little + assert_eq!(get_contract(&contract.addr).extra_deposit(), 16 + 32 + 2 + 1); + }); +} + +#[test] +fn cannot_self_destruct_while_live() { + let (binary, _code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + // Check that the BOB contract has been instantiated. + get_contract(&addr); + + // Call BOB with input data, forcing it make a recursive call to itself to + // self-destruct, resulting in a trap. + assert_err_ignore_postinfo!( + builder::call(addr).data(vec![0]).build(), + Error::::ContractTrapped, + ); + + // Check that BOB is still there. + get_contract(&addr); + }); +} + +#[test] +fn self_destruct_works() { + let (binary, code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(1_000).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&DJANGO_FALLBACK, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let contract = builder::bare_instantiate(Code::Upload(binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + let hold_balance = contract_base_deposit(&contract.addr); + + // Check that the BOB contract has been instantiated. + let _ = get_contract(&contract.addr); + + // Drop all previous events + initialize_block(2); + + // Call BOB without input data which triggers termination. + assert_matches!(builder::call(contract.addr).build(), Ok(_)); + + // Check that code is still there but refcount dropped to zero. + assert_refcount!(&code_hash, 0); + + // Check that account is gone + assert!(get_contract_checked(&contract.addr).is_none()); + assert_eq!(::Currency::total_balance(&contract.account_id), 0); + + // Check that the beneficiary (django) got remaining balance. + assert_eq!( + ::Currency::free_balance(DJANGO_FALLBACK), + 1_000_000 + 100_000 + min_balance + ); + + // Check that the Alice is missing Django's benefit. Within ALICE's total balance + // there's also the code upload deposit held. + assert_eq!( + ::Currency::total_balance(&ALICE), + 1_000_000 - (100_000 + min_balance) + ); + + pretty_assertions::assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: contract.account_id.clone(), + dest: ALICE, + amount: hold_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::KilledAccount { + account: contract.account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: contract.account_id.clone(), + to: DJANGO_FALLBACK, + amount: 100_000 + min_balance, + }), + topics: vec![], + }, + ], + ); + }); +} + +// This tests that one contract cannot prevent another from self-destructing by sending it +// additional funds after it has been drained. +#[test] +fn destroy_contract_and_transfer_funds() { + let (callee_binary, callee_code_hash) = compile_module("self_destruct").unwrap(); + let (caller_binary, _caller_code_hash) = compile_module("destroy_and_transfer").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create code hash for bob to instantiate + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + callee_binary.clone(), + deposit_limit::(), + ) + .unwrap(); + + // This deploys the BOB contract, which in turn deploys the CHARLIE contract during + // construction. + let Contract { addr: addr_bob, .. } = + builder::bare_instantiate(Code::Upload(caller_binary)) + .native_value(200_000) + .data(callee_code_hash.as_ref().to_vec()) + .build_and_unwrap_contract(); + + // Check that the CHARLIE contract has been instantiated. + let salt = [47; 32]; // hard coded in fixture. + let addr_charlie = create2(&addr_bob, &callee_binary, &[], &salt); + get_contract(&addr_charlie); + + // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. + assert_ok!(builder::call(addr_bob).data(addr_charlie.encode()).build()); + + // Check that CHARLIE has moved on to the great beyond (ie. died). + assert!(get_contract_checked(&addr_charlie).is_none()); + }); +} + +#[test] +fn cannot_self_destruct_in_constructor() { + let (binary, _) = compile_module("self_destructing_constructor").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Fail to instantiate the BOB because the constructor calls seal_terminate. + assert_err_ignore_postinfo!( + builder::instantiate_with_code(binary).value(100_000).build(), + Error::::TerminatedInConstructor, + ); + }); +} + +#[test] +fn crypto_hash_keccak_256() { + let (binary, _code_hash) = compile_module("crypto_hash_keccak_256").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the CRYPTO_HASH_KECCAK_256 contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + // Perform the call. + let input = b"_DEAD_BEEF"; + use sp_io::hashing::*; + // Wraps a hash function into a more dynamic form usable for testing. + macro_rules! dyn_hash_fn { + ($name:ident) => { + Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice()) + }; + } + // The hash function and its associated output byte lengths. + let hash_fn: Box Box<[u8]>> = dyn_hash_fn!(keccak_256); + let expected_size: usize = 32; + // Test the hash function for the input: "_DEAD_BEEF" + let result = builder::bare_call(addr).data(input.to_vec()).build_and_unwrap_result(); + assert!(!result.did_revert()); + let expected = hash_fn(input.as_ref()); + assert_eq!(&result.data[..expected_size], &*expected); + }) +} + +#[test] +fn transfer_return_code() { + let (binary, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let contract = builder::bare_instantiate(Code::Upload(binary)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + // Contract has only the minimal balance so any transfer will fail. + ::Currency::set_balance(&contract.account_id, min_balance); + let result = builder::bare_call(contract.addr).build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + }); +} + +#[test] +fn call_return_code() { + let (caller_code, _caller_hash) = compile_module("call_return_code").unwrap(); + let (callee_code, _callee_hash) = compile_module("ok_trap_revert").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + + let bob = builder::bare_instantiate(Code::Upload(caller_code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + // BOB cannot pay the ed which is needed to pull DJANGO into existence + // this does trap the caller instead of returning an error code + // reasoning is that this error state does not exist on eth where + // ed does not exist. We hide this fact from the contract. + let result = builder::bare_call(bob.addr) + .data((DJANGO_ADDR, u256_bytes(1)).encode()) + .origin(RuntimeOrigin::signed(BOB)) + .build(); + assert_err!(result.result, >::StorageDepositNotEnoughFunds); + + // Contract calls into Django which is no valid contract + // This will be a balance transfer into a new account + // with more than the contract has which will make the transfer fail + let value = Pallet::::convert_native_to_evm(min_balance * 200); + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&DJANGO_ADDR) + .iter() + .chain(&value.to_little_endian()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Sending below the minimum balance should result in success. + // The ED is charged from the call origin. + let alice_before = get_balance(&ALICE_FALLBACK); + assert_eq!(get_balance(&DJANGO_FALLBACK), 0); + + let value = Pallet::::convert_native_to_evm(1u64); + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&DJANGO_ADDR) + .iter() + .chain(&value.to_little_endian()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::Success); + assert_eq!(get_balance(&DJANGO_FALLBACK), min_balance + 1); + assert_eq!(get_balance(&ALICE_FALLBACK), alice_before - min_balance); + + let django = builder::bare_instantiate(Code::Upload(callee_code)) + .origin(RuntimeOrigin::signed(CHARLIE)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + // Sending more than the contract has will make the transfer fail. + let value = Pallet::::convert_native_to_evm(min_balance * 300); + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&value.to_little_endian()) + .chain(&0u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Contract has enough balance but callee reverts because "1" is passed. + ::Currency::set_balance(&bob.account_id, min_balance + 1000); + let value = Pallet::::convert_native_to_evm(5u64); + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&value.to_little_endian()) + .chain(&1u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeReverted); + + // Contract has enough balance but callee traps because "2" is passed. + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&value.to_little_endian()) + .chain(&2u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); + }); +} + +#[test] +fn instantiate_return_code() { + let (caller_code, _caller_hash) = compile_module("instantiate_return_code").unwrap(); + let (callee_code, callee_hash) = compile_module("ok_trap_revert").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + let callee_hash = callee_hash.as_ref().to_vec(); + + assert_ok!(builder::instantiate_with_code(callee_code).value(min_balance * 100).build()); + + let contract = builder::bare_instantiate(Code::Upload(caller_code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + // bob cannot pay the ED to create the contract as he has no money + // this traps the caller rather than returning an error + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) + .origin(RuntimeOrigin::signed(BOB)) + .build(); + assert_err!(result.result, >::StorageDepositNotEnoughFunds); + + // Contract has only the minimal balance so any transfer will fail. + ::Currency::set_balance(&contract.account_id, min_balance); + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Contract has enough balance but the passed code hash is invalid + ::Currency::set_balance(&contract.account_id, min_balance + 10_000); + let result = builder::bare_call(contract.addr).data(vec![0; 36]).build(); + assert_err!(result.result, >::CodeNotFound); + + // Contract has enough balance but callee reverts because "1" is passed. + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeReverted); + + // Contract has enough balance but callee traps because "2" is passed. + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); + + // Contract instantiation succeeds + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, 0); + + // Contract instantiation fails because the same salt is being used again. + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&0u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::DuplicateContractAddress); + }); +} + +#[test] +fn lazy_removal_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let contract = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + let info = get_contract(&contract.addr); + let trie = &info.child_trie_info(); + + // Put value into the contracts child trie + child::put(trie, &[99], &42); + + // Terminate the contract + assert_ok!(builder::call(contract.addr).build()); + + // Contract info should be gone + assert!(!>::contains_key(&contract.addr)); + + // But value should be still there as the lazy removal did not run, yet. + assert_matches!(child::get(trie, &[99]), Some(42)); + + // Run the lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); + + // Value should be gone now + assert_matches!(child::get::(trie, &[99]), None); + }); +} + +#[test] +fn lazy_batch_removal_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; + + for i in 0..3u8 { + let contract = builder::bare_instantiate(Code::Upload(code.clone())) + .native_value(min_balance * 100) + .salt(Some([i; 32])) + .build_and_unwrap_contract(); + + let info = get_contract(&contract.addr); + let trie = &info.child_trie_info(); + + // Put value into the contracts child trie + child::put(trie, &[99], &42); + + // Terminate the contract. Contract info should be gone, but value should be still + // there as the lazy removal did not run, yet. + assert_ok!(builder::call(contract.addr).build()); + + assert!(!>::contains_key(&contract.addr)); + assert_matches!(child::get(trie, &[99]), Some(42)); + + tries.push(trie.clone()) + } + + // Run single lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); + + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } + }); +} + +#[test] +fn ref_time_left_api_works() { + let (code, _) = compile_module("ref_time_left").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor calls ref_time_left twice and asserts it to decrease + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the ref_time returned by the ref_time_left API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + + let returned_value = u64::from_le_bytes(received.data[..8].try_into().unwrap()); + assert!(returned_value > 0); + assert!(returned_value < GAS_LIMIT.ref_time()); + }); +} + +#[test] +fn lazy_removal_partial_remove_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + + // We create a contract with some extra keys above the weight limit + let extra_keys = 7u32; + let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); + let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); + let vals: Vec<_> = (0..max_keys + extra_keys) + .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) + .collect(); + + let mut ext = ExtBuilder::default().existential_deposit(50).build(); + + let trie = ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + let info = get_contract(&addr); + + // Put value into the contracts child trie + for val in &vals { + info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); + } + AccountInfo::::insert_contract(&addr, info.clone()); + + // Terminate the contract + assert_ok!(builder::call(addr).build()); + + // Contract info should be gone + assert!(!>::contains_key(&addr)); + + let trie = info.child_trie_info(); + + // But value should be still there as the lazy removal did not run, yet. + for val in &vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); + } + + trie.clone() + }); + + // The lazy removal limit only applies to the backend but not to the overlay. + // This commits all keys from the overlay to the backend. + ext.commit_all().unwrap(); + + ext.execute_with(|| { + // Run the lazy removal + ContractInfo::::process_deletion_queue_batch(&mut meter); + + // Weight should be exhausted because we could not even delete all keys + assert!(!meter.can_consume(weight_per_key)); + + let mut num_deleted = 0u32; + let mut num_remaining = 0u32; + + for val in &vals { + match child::get::(&trie, &blake2_256(&val.0)) { + None => num_deleted += 1, + Some(x) if x == val.1 => num_remaining += 1, + Some(_) => panic!("Unexpected value in contract storage"), + } + } + + // All but one key is removed + assert_eq!(num_deleted + num_remaining, vals.len() as u32); + assert_eq!(num_deleted, max_keys); + assert_eq!(num_remaining, extra_keys); + }); +} + +#[test] +fn lazy_removal_does_no_run_on_low_remaining_weight() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + let info = get_contract(&addr); + let trie = &info.child_trie_info(); + + // Put value into the contracts child trie + child::put(trie, &[99], &42); + + // Terminate the contract + assert_ok!(builder::call(addr).build()); + + // Contract info should be gone + assert!(!>::contains_key(&addr)); + + // But value should be still there as the lazy removal did not run, yet. + assert_matches!(child::get(trie, &[99]), Some(42)); + + // Assign a remaining weight which is too low for a successful deletion of the contract + let low_remaining_weight = + <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); + + // Run the lazy removal + Contracts::on_idle(System::block_number(), low_remaining_weight); + + // Value should still be there, since remaining weight was too low for removal + assert_matches!(child::get::(trie, &[99]), Some(42)); + + // Run the lazy removal while deletion_queue is not full + Contracts::on_initialize(System::block_number()); + + // Value should still be there, since deletion_queue was not full + assert_matches!(child::get::(trie, &[99]), Some(42)); + + // Run on_idle with max remaining weight, this should remove the value + Contracts::on_idle(System::block_number(), Weight::MAX); + + // Value should be gone + assert_matches!(child::get::(trie, &[99]), None); + }); +} + +#[test] +fn lazy_removal_does_not_use_all_weight() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + + let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); + let mut ext = ExtBuilder::default().existential_deposit(50).build(); + + let (trie, vals, weight_per_key) = ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + let info = get_contract(&addr); + let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); + assert!(max_keys > 0); + + // We create a contract with one less storage item than we can remove within the limit + let vals: Vec<_> = (0..max_keys - 1) + .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) + .collect(); + + // Put value into the contracts child trie + for val in &vals { + info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); + } + AccountInfo::::insert_contract(&addr, info.clone()); + + // Terminate the contract + assert_ok!(builder::call(addr).build()); + + // Contract info should be gone + assert!(!>::contains_key(&addr)); + + let trie = info.child_trie_info(); + + // But value should be still there as the lazy removal did not run, yet. + for val in &vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); + } + + (trie, vals, weight_per_key) + }); + + // The lazy removal limit only applies to the backend but not to the overlay. + // This commits all keys from the overlay to the backend. + ext.commit_all().unwrap(); + + ext.execute_with(|| { + // Run the lazy removal + ContractInfo::::process_deletion_queue_batch(&mut meter); + let base_weight = + <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); + assert_eq!(meter.consumed(), weight_per_key.mul(vals.len() as _) + base_weight); + + // All the keys are removed + for val in vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); + } + }); +} + +#[test] +fn deletion_queue_ring_buffer_overflow() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + let mut ext = ExtBuilder::default().existential_deposit(50).build(); + + // setup the deletion queue with custom counters + ext.execute_with(|| { + let queue = DeletionQueueManager::from_test_values(u32::MAX - 1, u32::MAX - 1); + >::set(queue); + }); + + // commit the changes to the storage + ext.commit_all().unwrap(); + + ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; + + // add 3 contracts to the deletion queue + for i in 0..3u8 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) + .native_value(min_balance * 100) + .salt(Some([i; 32])) + .build_and_unwrap_contract(); + + let info = get_contract(&addr); + let trie = &info.child_trie_info(); + + // Put value into the contracts child trie + child::put(trie, &[99], &42); + + // Terminate the contract. Contract info should be gone, but value should be still + // there as the lazy removal did not run, yet. + assert_ok!(builder::call(addr).build()); + + assert!(!>::contains_key(&addr)); + assert_matches!(child::get(trie, &[99]), Some(42)); + + tries.push(trie.clone()) + } + + // Run single lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); + + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } + + // insert and delete counter values should go from u32::MAX - 1 to 1 + assert_eq!(>::get().as_test_tuple(), (1, 1)); + }) +} +#[test] +fn refcounter() { + let (binary, code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Create two contracts with the same code and check that they do in fact share it. + let Contract { addr: addr0, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) + .native_value(min_balance * 100) + .salt(Some([0; 32])) + .build_and_unwrap_contract(); + let Contract { addr: addr1, .. } = builder::bare_instantiate(Code::Upload(binary.clone())) + .native_value(min_balance * 100) + .salt(Some([1; 32])) + .build_and_unwrap_contract(); + assert_refcount!(code_hash, 2); + + // Sharing should also work with the usual instantiate call + let Contract { addr: addr2, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .native_value(min_balance * 100) + .salt(Some([2; 32])) + .build_and_unwrap_contract(); + assert_refcount!(code_hash, 3); + + // Terminating one contract should decrement the refcount + assert_ok!(builder::call(addr0).build()); + assert_refcount!(code_hash, 2); + + // remove another one + assert_ok!(builder::call(addr1).build()); + assert_refcount!(code_hash, 1); + + // Pristine code should still be there + PristineCode::::get(code_hash).unwrap(); + + // remove the last contract + assert_ok!(builder::call(addr2).build()); + assert_refcount!(code_hash, 0); + + // refcount is `0` but code should still exists because it needs to be removed manually + assert!(crate::PristineCode::::contains_key(&code_hash)); + }); +} + +#[test] +fn gas_estimation_for_subcalls() { + let (caller_code, _caller_hash) = compile_module("call_with_limit").unwrap(); + let (dummy_code, _callee_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); + + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(caller_code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + let Contract { addr: addr_dummy, .. } = builder::bare_instantiate(Code::Upload(dummy_code)) + .native_value(min_balance * 100) + .build_and_unwrap_contract(); + + // Run the test for all of those weight limits for the subcall + let weights = [ + Weight::MAX, + GAS_LIMIT, + GAS_LIMIT * 2, + GAS_LIMIT / 5, + Weight::from_parts(u64::MAX, GAS_LIMIT.proof_size()), + Weight::from_parts(GAS_LIMIT.ref_time(), u64::MAX), + ]; + + let (sub_addr, sub_input) = (addr_dummy.as_ref(), vec![]); + + for weight in weights { + let input: Vec = sub_addr + .iter() + .cloned() + .chain(weight.ref_time().to_le_bytes()) + .chain(weight.proof_size().to_le_bytes()) + .chain(sub_input.clone()) + .collect(); + + // Call in order to determine the gas that is required for this call + let result_orig = builder::bare_call(addr_caller).data(input.clone()).build(); + assert_ok!(&result_orig.result); + assert_eq!(result_orig.gas_required, result_orig.gas_consumed); + + // Make the same call using the estimated gas. Should succeed. + let result = builder::bare_call(addr_caller) + .gas_limit(result_orig.gas_required) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) + .data(input.clone()) + .build(); + assert_ok!(&result.result); + + // Check that it fails with too little ref_time + let result = builder::bare_call(addr_caller) + .gas_limit(result_orig.gas_required.sub_ref_time(1)) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) + .data(input.clone()) + .build(); + assert_err!(result.result, >::OutOfGas); + + // Check that it fails with too little proof_size + let result = builder::bare_call(addr_caller) + .gas_limit(result_orig.gas_required.sub_proof_size(1)) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) + .data(input.clone()) + .build(); + assert_err!(result.result, >::OutOfGas); + } + }); +} + +#[test] +fn call_runtime_reentrancy_guarded() { + use crate::precompiles::Precompile; + use alloy_core::sol_types::SolInterface; + use precompiles::{INoInfo, NoInfo}; + + let precompile_addr = H160(NoInfo::::MATCHER.base_address()); + + let (callee_code, _callee_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(callee_code)) + .native_value(min_balance * 100) + .salt(Some([1; 32])) + .build_and_unwrap_contract(); + + // Call pallet_revive call() dispatchable + let call = RuntimeCall::Contracts(crate::Call::call { + dest: addr_callee, + value: 0, + gas_limit: GAS_LIMIT / 3, + storage_deposit_limit: deposit_limit::(), + data: vec![], + }) + .encode(); + + // Call runtime to re-enter back to contracts engine by + // calling dummy contract + let result = builder::bare_call(precompile_addr) + .data( + INoInfo::INoInfoCalls::callRuntime(INoInfo::callRuntimeCall { call: call.into() }) + .abi_encode(), + ) + .build(); + // Call to runtime should fail because of the re-entrancy guard + assert_err!(result.result, >::ReenteredPallet); + }); +} + +#[test] +fn sr25519_verify() { + let (binary, _code_hash) = compile_module("sr25519_verify").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the sr25519_verify contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(100_000) + .build_and_unwrap_contract(); + + let call_with = |message: &[u8; 11]| { + // Alice's signature for "hello world" + #[rustfmt::skip] + let signature: [u8; 64] = [ + 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247, + 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83, + 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255, + 228, 54, 115, 63, 30, 207, 205, 131, + ]; + + // Alice's public key + #[rustfmt::skip] + let public_key: [u8; 32] = [ + 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, + 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125, + ]; + + let mut params = vec![]; + params.extend_from_slice(&signature); + params.extend_from_slice(&public_key); + params.extend_from_slice(message); + + builder::bare_call(addr).data(params).build_and_unwrap_result() + }; + + // verification should succeed for "hello world" + assert_return_code!(call_with(&b"hello world"), RuntimeReturnCode::Success); + + // verification should fail for other messages + assert_return_code!(call_with(&b"hello worlD"), RuntimeReturnCode::Sr25519VerifyFailed); + }); +} + +#[test] +fn upload_code_works() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert!(!PristineCode::::contains_key(&code_hash)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + }); +} + +#[test] +fn upload_code_limit_too_low() { + let (binary, _code_hash) = compile_module("dummy").unwrap(); + let deposit_expected = expected_deposit(binary.len()); + let deposit_insufficient = deposit_expected.saturating_sub(1); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_insufficient,), + >::StorageDepositLimitExhausted, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn upload_code_not_enough_balance() { + let (binary, _code_hash) = compile_module("dummy").unwrap(); + let deposit_expected = expected_deposit(binary.len()); + let deposit_insufficient = deposit_expected.saturating_sub(1); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, deposit_insufficient); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,), + >::StorageDepositNotEnoughFunds, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn remove_code_works() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); + }); +} + +#[test] +fn remove_code_wrong_origin() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), + sp_runtime::traits::BadOrigin, + ); + }); +} + +#[test] +fn remove_code_in_use() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + assert_ok!(builder::instantiate_with_code(binary).build()); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), + >::CodeInUse, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn remove_code_not_found() { + let (_binary, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), + >::CodeNotFound, + ); + + assert_eq!(System::events(), vec![]); + }); +} + +#[test] +fn instantiate_with_zero_balance_works() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Drop previous events + initialize_block(2); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + + // Make sure the account exists even though no free balance was send + assert_eq!(::Currency::free_balance(&account_id), min_balance); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + contract_base_deposit(&addr) + ); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Held { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::CodeUploadDepositReserve, + ), + who: ALICE, + amount: 776, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: account_id, + transferred: 336, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn instantiate_with_below_existential_deposit_works() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let value = 50; + + // Drop previous events + initialize_block(2); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(value) + .build_and_unwrap_contract(); + + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + // Make sure the account exists even though not enough free balance was send + assert_eq!(::Currency::free_balance(&account_id), min_balance + value); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + value + contract_base_deposit(&addr) + ); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Held { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::CodeUploadDepositReserve, + ), + who: ALICE, + amount: 776, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: 50, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: account_id.clone(), + transferred: 336, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn storage_deposit_works() { + let (binary, _code_hash) = compile_module("multi_store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + let mut deposit = contract_base_deposit(&addr); + + // Drop previous events + initialize_block(2); + + // Create storage + assert_ok!(builder::call(addr).value(42).data((50u32, 20u32).encode()).build()); + // 4 is for creating 2 storage items + // 48 is for each of the keys + let charged0 = 4 + 50 + 20 + 48 + 48; + deposit += charged0; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + // Add more storage (but also remove some) + assert_ok!(builder::call(addr).data((100u32, 10u32).encode()).build()); + let charged1 = 50 - 10; + deposit += charged1; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + // Remove more storage (but also add some) + assert_ok!(builder::call(addr).data((10u32, 20u32).encode()).build()); + // -1 for numeric instability + let refunded0 = 90 - 10 - 1; + deposit -= refunded0; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: 42, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: account_id.clone(), + transferred: charged0, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: ALICE, + dest: account_id.clone(), + transferred: charged1, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::StorageDepositReserve, + ), + source: account_id.clone(), + dest: ALICE, + amount: refunded0, + }), + topics: vec![], + }, + ] + ); + }); +} + +#[test] +fn storage_deposit_callee_works() { + let (binary_caller, _code_hash_caller) = compile_module("call").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + assert_ok!(builder::call(addr_caller).data((100u32, &addr_callee).encode()).build()); + + let callee = get_contract(&addr_callee); + let deposit = DepositPerByte::get() * 100 + DepositPerItem::get() * 1 + 48; + + assert_eq!(Pallet::::evm_balance(&addr_caller), U256::zero()); + assert_eq!(callee.total_deposit(), deposit + contract_base_deposit(&addr_callee)); + }); +} + +#[test] +fn set_code_extrinsic() { + let (binary, code_hash) = compile_module("dummy").unwrap(); + let (new_binary, new_code_hash) = compile_module("crypto_hash_keccak_256").unwrap(); + + assert_ne!(code_hash, new_code_hash); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_binary, + deposit_limit::(), + )); + + // Drop previous events + initialize_block(2); + + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + + // only root can execute this extrinsic + assert_noop!( + Contracts::set_code(RuntimeOrigin::signed(ALICE), addr, new_code_hash), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // contract must exist + assert_noop!( + Contracts::set_code(RuntimeOrigin::root(), BOB_ADDR, new_code_hash), + >::ContractNotFound, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // new code hash must exist + assert_noop!( + Contracts::set_code(RuntimeOrigin::root(), addr, Default::default()), + >::CodeNotFound, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // successful call + assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr, new_code_hash)); + assert_eq!(get_contract(&addr).code_hash, new_code_hash); + assert_refcount!(&code_hash, 0); + assert_refcount!(&new_code_hash, 1); + }); +} + +#[test] +fn slash_cannot_kill_account() { + let (binary, _code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let value = 700; + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(value) + .build_and_unwrap_contract(); + + // Drop previous events + initialize_block(2); + + let info_deposit = contract_base_deposit(&addr); + + assert_eq!( + get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id), + info_deposit + ); + + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + value + min_balance + ); + + // Try to destroy the account of the contract by slashing the total balance. + // The account does not get destroyed because slashing only affects the balance held + // under certain `reason`. Slashing can for example happen if the contract takes part + // in staking. + let _ = ::Currency::slash( + &HoldReason::StorageDepositReserve.into(), + &account_id, + ::Currency::total_balance(&account_id), + ); + + // Slashing only removed the balance held. + assert_eq!(::Currency::total_balance(&account_id), value + min_balance); + }); +} + +#[test] +fn contract_reverted() { + let (binary, code_hash) = compile_module("return_with_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let flags = ReturnFlags::REVERT; + let buffer = [4u8, 8, 15, 16, 23, 42]; + let input = (flags.bits(), buffer).encode(); + + // We just upload the code for later use + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary.clone(), + deposit_limit::(), + )); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).data(input.clone()).build(), + >::ContractReverted, + ); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::instantiate_with_code(binary).data(input.clone()).build(), + >::ContractReverted, + ); + + // Calling directly: revert leads to success but the flags indicate the error + // This is just a different way of transporting the error that allows the read out + // the `data` which is only there on success. Obviously, the contract isn't + // instantiated. + let result = builder::bare_instantiate(Code::Existing(code_hash)) + .data(input.clone()) + .build_and_unwrap_result(); + assert_eq!(result.result.flags, flags); + assert_eq!(result.result.data, buffer); + assert!(!>::contains_key(result.addr)); + + // Pass empty flags and therefore successfully instantiate the contract for later use. + let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .data(ReturnFlags::empty().bits().encode()) + .build_and_unwrap_contract(); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::call(addr).data(input.clone()).build(), + >::ContractReverted, + ); + + // Calling directly: revert leads to success but the flags indicate the error + let result = builder::bare_call(addr).data(input).build_and_unwrap_result(); + assert_eq!(result.flags, flags); + assert_eq!(result.data, buffer); + }); +} + +#[test] +fn set_code_hash() { + let (binary, _) = compile_module("set_code_hash").unwrap(); + let (new_binary, new_code_hash) = compile_module("new_set_code_hash_contract").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: contract_addr, .. } = builder::bare_instantiate(Code::Upload(binary)) + .native_value(300_000) + .build_and_unwrap_contract(); + // upload new code + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_binary.clone(), + deposit_limit::(), + )); + + System::reset_events(); + + // First call sets new code_hash and returns 1 + let result = builder::bare_call(contract_addr) + .data(new_code_hash.as_ref().to_vec()) + .build_and_unwrap_result(); + assert_return_code!(result, 1); + + // Second calls new contract code that returns 2 + let result = builder::bare_call(contract_addr).build_and_unwrap_result(); + assert_return_code!(result, 2); + }); +} + +#[test] +fn storage_deposit_limit_is_enforced() { + let (binary, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Setting insufficient storage_deposit should fail. + assert_err!( + builder::bare_instantiate(Code::Upload(binary.clone())) + // expected deposit is 2 * ed + 3 for the call + .storage_deposit_limit((2 * min_balance + 3 - 1).into()) + .build() + .result, + >::StorageDepositLimitExhausted, + ); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + let info_deposit = contract_base_deposit(&addr); + // Check that the BOB contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + min_balance + ); + + // Create 1 byte of storage with a price of per byte, + // setting insufficient deposit limit, as it requires 3 Balance: + // 2 for the item added + 1 (value) + 48 (key) + assert_err_ignore_postinfo!( + builder::call(addr) + .storage_deposit_limit(50) + .data(1u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); + + // now with enough limit + assert_ok!(builder::call(addr) + .storage_deposit_limit(51) + .data(1u32.to_le_bytes().to_vec()) + .build()); + + // Use 4 more bytes of the storage for the same item, which requires 4 Balance. + // Should fail as DefaultDepositLimit is 3 and hence isn't enough. + assert_err_ignore_postinfo!( + builder::call(addr) + .storage_deposit_limit(3) + .data(5u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); + }); +} + +#[test] +fn deposit_limit_in_nested_calls() { + let (binary_caller, _code_hash_caller) = compile_module("create_storage_and_call").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + // Create 100 bytes of storage with a price of per byte + // This is 100 Balance + 2 Balance for the item + // 48 for the key + assert_ok!(builder::call(addr_callee) + .storage_deposit_limit(102 + 48) + .data(100u32.to_le_bytes().to_vec()) + .build()); + + // We do not remove any storage but add a storage item of 12 bytes in the caller + // contract. This would cost 12 + 2 + 72 = 86 Balance. + // The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it. + // This should fail as the specified parent's limit is less than the cost: 13 < + // 14. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(85) + .data((100u32, &addr_callee, U256::MAX).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); + + // Now we specify the parent's limit high enough to cover the caller's storage + // additions. However, we use a single byte more in the callee, hence the storage + // deposit should be 87 Balance. + // The nested call doesn't get a special limit, which is set by passing `u64::MAX` to it. + // This should fail as the specified parent's limit is less than the cost: 86 < 87 + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(86) + .data((101u32, &addr_callee, &U256::MAX).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); + + // The parents storage deposit limit doesn't matter as the sub calls limit + // is enforced eagerly. However, we set a special deposit limit of 1 Balance for the + // nested call. This should fail as callee adds up 2 bytes to the storage, meaning + // that the nested call should have a deposit limit of at least 2 Balance. The + // sub-call should be rolled back, which is covered by the next test case. + let ret = builder::bare_call(addr_caller) + .storage_deposit_limit(DepositLimit::Balance(u64::MAX)) + .data((102u32, &addr_callee, U256::from(1u64)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + + // Refund in the callee contract but not enough to cover the Balance required by the + // caller. Note that if previous sub-call wouldn't roll back, this call would pass + // making the test case fail. We don't set a special limit for the nested call here. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(0) + .data((87u32, &addr_callee, &U256::MAX.to_little_endian()).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); + + let _ = ::Currency::set_balance(&ALICE, 511); + + // Require more than the sender's balance. + // Limit the sub call to little balance so it should fail in there + let ret = builder::bare_call(addr_caller) + .data((416, &addr_callee, U256::from(1u64)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + + // Free up enough storage in the callee so that the caller can create a new item + // We set the special deposit limit of 1 Balance for the nested call, which isn't + // enforced as callee frees up storage. This should pass. + assert_ok!(builder::call(addr_caller) + .storage_deposit_limit(1) + .data((0u32, &addr_callee, U256::from(1u64)).encode()) + .build()); + }); +} + +#[test] +fn deposit_limit_in_nested_instantiate() { + let (binary_caller, _code_hash_caller) = + compile_module("create_storage_and_instantiate").unwrap(); + let (binary_callee, code_hash_callee) = compile_module("store_deploy").unwrap(); + const ED: u64 = 5; + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 1_000_000); + // Create caller contract + let Contract { addr: addr_caller, account_id: caller_id } = + builder::bare_instantiate(Code::Upload(binary_caller)) + .native_value(10_000) // this balance is later passed to the deployed contract + .build_and_unwrap_contract(); + // Deploy a contract to get its occupied storage size + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(binary_callee)) + .data(vec![0, 0, 0, 0]) + .build_and_unwrap_contract(); + + // This is the deposit we expect to be charged just for instantiatiting the callee. + // + // - callee_info_len + 2 for storing the new contract info + // - the deposit for depending on a code hash + // - ED for deployed contract account + // - 2 for the storage item of 0 bytes being created in the callee constructor + // - 48 for the key + let callee_min_deposit = { + let callee_info_len = + AccountInfo::::load_contract(&addr).unwrap().encoded_size() as u64; + let code_deposit = lockup_deposit(&code_hash_callee); + callee_info_len + code_deposit + 2 + ED + 2 + 48 + }; + + // The parent just stores an item of the passed size so at least + // we need to pay for the item itself. + let caller_min_deposit = callee_min_deposit + 2 + 48; + + // Fail in callee. + // + // We still fail in the sub call because we enforce limits on return from a contract. + // Sub calls return first to they are checked first. + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(0)) + .data((&code_hash_callee, 100u32, &U256::MAX.to_little_endian()).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + // The charges made on instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Fail in the caller. + // + // For that we need to supply enough storage deposit so that the sub call + // succeeds but the parent call runs out of storage. + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(callee_min_deposit)) + .data((&code_hash_callee, 0u32, &U256::MAX.to_little_endian()).encode()) + .build(); + assert_err!(ret.result, >::StorageDepositLimitExhausted); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Fail in the callee with bytes. + // + // Same as above but stores one byte in both caller and callee. + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(caller_min_deposit + 1)) + .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Fail in the caller with bytes. + // + // Same as above but stores one byte in both caller and callee. + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(callee_min_deposit + 1)) + .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit + 1)).encode()) + .build(); + assert_err!(ret.result, >::StorageDepositLimitExhausted); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Set enough deposit limit for the child instantiate. This should succeed. + let result = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit((caller_min_deposit + 2).into()) + .data((&code_hash_callee, 1u32, U256::from(callee_min_deposit + 1)).encode()) + .build(); + + let returned = result.result.unwrap(); + assert!(!returned.did_revert()); + + // All balance of the caller except ED has been transferred to the callee. + // No deposit has been taken from it. + assert_eq!(::Currency::free_balance(&caller_id), ED); + // Get address of the deployed contract. + let addr_callee = H160::from_slice(&returned.data[0..20]); + let callee_account_id = ::AddressMapper::to_account_id(&addr_callee); + // 10_000 should be sent to callee from the caller contract, plus ED to be sent from the + // origin. + assert_eq!(::Currency::free_balance(&callee_account_id), 10_000 + ED); + // The origin should be charged with what the outer call consumed + assert_eq!( + ::Currency::free_balance(&BOB), + 1_000_000 - (caller_min_deposit + 2), + ); + assert_eq!(result.storage_deposit.charge_or_zero(), (caller_min_deposit + 2)) + }); +} + +#[test] +fn deposit_limit_honors_liquidity_restrictions() { + let (binary, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let bobs_balance = 1_000; + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, bobs_balance); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + let info_deposit = contract_base_deposit(&addr); + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + min_balance + ); + + // check that the hold is honored + ::Currency::hold( + &HoldReason::CodeUploadDepositReserve.into(), + &BOB, + bobs_balance - min_balance, + ) + .unwrap(); + assert_err_ignore_postinfo!( + builder::call(addr) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(10_000) + .data(100u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(::Currency::free_balance(&BOB), min_balance); + }); +} + +#[test] +fn deposit_limit_honors_existential_deposit() { + let (binary, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 300); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + let info_deposit = contract_base_deposit(&addr); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + info_deposit + ); + + // check that the deposit can't bring the account below the existential deposit + assert_err_ignore_postinfo!( + builder::call(addr) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(10_000) + .data(100u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(::Currency::free_balance(&BOB), 300); + }); +} + +#[test] +fn native_dependency_deposit_works() { + let (binary, code_hash) = compile_module("set_code_hash").unwrap(); + let (dummy_binary, dummy_code_hash) = compile_module("dummy").unwrap(); + + // Test with both existing and uploaded code + for code in [Code::Upload(binary.clone()), Code::Existing(code_hash)] { + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let lockup_deposit_percent = CodeHashLockupDepositPercent::get(); + + // Upload the dummy contract, + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + dummy_binary.clone(), + deposit_limit::(), + ) + .unwrap(); + + // Upload `set_code_hash` contracts if using Code::Existing. + let add_upload_deposit = match code { + Code::Existing(_) => { + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary.clone(), + deposit_limit::(), + ) + .unwrap(); + false + }, + Code::Upload(_) => true, + }; + + // Instantiate the set_code_hash contract. + let res = builder::bare_instantiate(code).build(); + + let addr = res.result.unwrap().addr; + let account_id = ::AddressMapper::to_account_id(&addr); + let base_deposit = contract_base_deposit(&addr); + let upload_deposit = get_code_deposit(&code_hash); + let extra_deposit = add_upload_deposit.then(|| upload_deposit).unwrap_or_default(); + + assert_eq!( + res.storage_deposit.charge_or_zero(), + extra_deposit + base_deposit + Contracts::min_balance() + ); + + // call set_code_hash + builder::bare_call(addr) + .data(dummy_code_hash.encode()) + .build_and_unwrap_result(); + + // Check updated storage_deposit due to code size changes + let deposit_diff = lockup_deposit_percent.mul_ceil(get_code_deposit(&code_hash)) - + lockup_deposit_percent.mul_ceil(get_code_deposit(&dummy_code_hash)); + let new_base_deposit = contract_base_deposit(&addr); + assert_ne!(deposit_diff, 0); + assert_eq!(base_deposit - new_base_deposit, deposit_diff); + + assert_eq!( + get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id), + new_base_deposit + ); + }); + } +} + +#[test] +fn block_hash_works() { + let (code, _) = compile_module("block_hash").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // The genesis config sets to the block number to 1 + let block_hash = [1; 32]; + frame_system::BlockHash::::insert( + &crate::BlockNumberFor::::from(0u32), + ::Hash::from(&block_hash), + ); + assert_ok!(builder::call(addr) + .data((U256::zero(), H256::from(block_hash)).encode()) + .build()); + + // A block number out of range returns the zero value + assert_ok!(builder::call(addr).data((U256::from(1), H256::zero()).encode()).build()); + }); +} + +#[test] +fn block_author_works() { + let (code, _) = compile_module("block_author").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // The fixture asserts the input to match the find_author API method output. + assert_ok!(builder::call(addr).data(EVE_ADDR.encode()).build()); + }); +} + +#[test] +fn root_cannot_upload_code() { + let (binary, _) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::upload_code(RuntimeOrigin::root(), binary, deposit_limit::()), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn root_cannot_remove_code() { + let (_, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::remove_code(RuntimeOrigin::root(), code_hash), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn signed_cannot_set_code() { + let (_, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::set_code(RuntimeOrigin::signed(ALICE), BOB_ADDR, code_hash), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn none_cannot_call_code() { + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::call(BOB_ADDR).origin(RuntimeOrigin::none()).build(), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn root_can_call() { + let (binary, _) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary)).build_and_unwrap_contract(); + + // Call the contract. + assert_ok!(builder::call(addr).origin(RuntimeOrigin::root()).build()); + }); +} + +#[test] +fn root_cannot_instantiate_with_code() { + let (binary, _) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::instantiate_with_code(binary).origin(RuntimeOrigin::root()).build(), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn root_cannot_instantiate() { + let (_, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).origin(RuntimeOrigin::root()).build(), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn only_upload_origin_can_upload() { + let (binary, _) = compile_module("dummy").unwrap(); + UploadAccount::set(Some(ALICE)); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&BOB, 1_000_000); + + assert_err!( + Contracts::upload_code(RuntimeOrigin::root(), binary.clone(), deposit_limit::(),), + DispatchError::BadOrigin + ); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(BOB), + binary.clone(), + deposit_limit::(), + ), + DispatchError::BadOrigin + ); + + // Only alice is allowed to upload contract code. + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary.clone(), + deposit_limit::(), + )); + }); +} + +#[test] +fn only_instantiation_origin_can_instantiate() { + let (code, code_hash) = compile_module("dummy").unwrap(); + InstantiateAccount::set(Some(ALICE)); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&BOB, 1_000_000); + + assert_err_ignore_postinfo!( + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::root()) + .build(), + DispatchError::BadOrigin + ); + + assert_err_ignore_postinfo!( + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .build(), + DispatchError::BadOrigin + ); + + // Only Alice can instantiate + assert_ok!(builder::instantiate_with_code(code).build()); + + // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).origin(RuntimeOrigin::signed(BOB)).build(), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn balance_of_api() { + let (binary, _code_hash) = compile_module("balance_of").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&ALICE_FALLBACK, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); + + // The fixture asserts a non-zero returned free balance of the account; + // The ALICE_FALLBACK account is endowed; + // Hence we should not revert + assert_ok!(builder::call(addr).data(ALICE_ADDR.0.to_vec()).build()); + + // The fixture asserts a non-zero returned free balance of the account; + // The ETH_BOB account is not endowed; + // Hence we should revert + assert_err_ignore_postinfo!( + builder::call(addr).data(BOB_ADDR.0.to_vec()).build(), + >::ContractTrapped + ); + }); +} + +#[test] +fn balance_api_returns_free_balance() { + let (binary, _code_hash) = compile_module("balance").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract without any extra balance. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); + + let value = 0; + // Call BOB which makes it call the balance runtime API. + // The contract code asserts that the returned balance is 0. + assert_ok!(builder::call(addr).value(value).build()); + + let value = 1; + // Calling with value will trap the contract. + assert_err_ignore_postinfo!( + builder::call(addr).value(value).build(), + >::ContractTrapped + ); + }); +} + +#[test] +fn call_depth_is_enforced() { + let (binary, _code_hash) = compile_module("recurse").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let extra_recursions = 1024; + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(binary.to_vec())).build_and_unwrap_contract(); + + // takes the number of recursions + // returns the number of left over recursions + assert_eq!( + u32::from_le_bytes( + builder::bare_call(addr) + .data((limits::CALL_STACK_DEPTH + extra_recursions).encode()) + .build_and_unwrap_result() + .data + .try_into() + .unwrap() + ), + // + 1 because when the call depth is reached the caller contract is trapped without + // the ability to return any data. hence the last call frame is untracked. + extra_recursions + 1, + ); + }); +} + +#[test] +fn gas_consumed_is_linear_for_nested_calls() { + let (code, _code_hash) = compile_module("recurse").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let [gas_0, gas_1, gas_2, gas_max] = { + [0u32, 1u32, 2u32, limits::CALL_STACK_DEPTH] + .iter() + .map(|i| { + let result = builder::bare_call(addr).data(i.encode()).build(); + assert_eq!( + u32::from_le_bytes(result.result.unwrap().data.try_into().unwrap()), + 0 + ); + result.gas_consumed + }) + .collect::>() + .try_into() + .unwrap() + }; + + let gas_per_recursion = gas_2.checked_sub(&gas_1).unwrap(); + assert_eq!(gas_max, gas_0 + gas_per_recursion * limits::CALL_STACK_DEPTH as u64); + }); +} + +#[test] +fn read_only_call_cannot_store() { + let (binary_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + // Read-only call fails when modifying storage. + assert_err_ignore_postinfo!( + builder::call(addr_caller).data((&addr_callee, 100u32).encode()).build(), + >::ContractTrapped + ); + }); +} + +#[test] +fn read_only_call_cannot_transfer() { + let (binary_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + // Read-only call fails when a non-zero value is set. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data( + (addr_callee, pallet_revive_uapi::CallFlags::READ_ONLY.bits(), 100u64).encode() + ) + .build(), + >::StateChangeDenied + ); + }); +} + +#[test] +fn read_only_subsequent_call_cannot_store() { + let (binary_read_only_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (binary_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_read_only_caller)) + .build_and_unwrap_contract(); + let Contract { addr: addr_subsequent_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + // Subsequent call input. + let input = (&addr_callee, pallet_revive_uapi::CallFlags::empty().bits(), 0u64, 100u32); + + // Read-only call fails when modifying storage. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((&addr_subsequent_caller, input).encode()) + .build(), + >::ContractTrapped + ); + }); +} + +#[test] +fn read_only_call_works() { + let (binary_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (binary_callee, _code_hash_callee) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(binary_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + assert_ok!(builder::call(addr_caller).data(addr_callee.encode()).build()); + }); +} + +#[test] +fn create1_with_value_works() { + let (code, code_hash) = compile_module("create1_with_value").unwrap(); + let value = 42; + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: Deploys itself using create1 and the expected value + assert_ok!(builder::call(addr).value(value).data(code_hash.encode()).build()); + + // We should see the expected balance at the expected account + let address = crate::address::create1(&addr, 1); + let account_id = ::AddressMapper::to_account_id(&address); + let usable_balance = ::Currency::usable_balance(&account_id); + assert_eq!(usable_balance, value); + }); +} + +#[test] +fn gas_price_api_works() { + let (code, _) = compile_module("gas_price").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the gas price API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data[..].try_into().unwrap()), u64::from(GAS_PRICE)); + }); +} + +#[test] +fn base_fee_api_works() { + let (code, _) = compile_module("base_fee").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the base fee API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(received.data[..].try_into().unwrap()), U256::zero()); + }); +} + +#[test] +fn call_data_size_api_works() { + let (code, _) = compile_module("call_data_size").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the call data size API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 0); + + let received = builder::bare_call(addr).data(vec![1; 256]).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 256); + }); +} + +#[test] +fn call_data_copy_api_works() { + let (code, _) = compile_module("call_data_copy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call fixture: Expects an input of [255; 32] and executes tests. + assert_ok!(builder::call(addr).data(vec![255; 32]).build()); + }); +} + +#[test] +fn static_data_limit_is_enforced() { + let (oom_rw_trailing, _) = compile_module("oom_rw_trailing").unwrap(); + let (oom_rw_included, _) = compile_module("oom_rw_included").unwrap(); + let (oom_ro, _) = compile_module("oom_ro").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + oom_rw_trailing, + deposit_limit::(), + ), + >::StaticMemoryTooLarge + ); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + oom_rw_included, + deposit_limit::(), + ), + >::BlobTooLarge + ); + + assert_err!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), oom_ro, deposit_limit::(),), + >::BlobTooLarge + ); + }); +} + +#[test] +fn call_diverging_out_len_works() { + let (code, _) = compile_module("call_diverging_out_len").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It will issue calls and deploys, asserting on + // correct output if the supplied output length was smaller than + // than what the callee returned. + assert_ok!(builder::call(addr).build()); + }); +} + +#[test] +fn chain_id_works() { + let (code, _) = compile_module("chain_id").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let chain_id = U256::from(::ChainId::get()); + let received = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_result(); + assert_eq!(received.result.data, chain_id.encode()); + }); +} + +#[test] +fn call_data_load_api_works() { + let (code, _) = compile_module("call_data_load").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It reads a byte for the offset and then returns + // what call data load returned using this byte as the offset. + let input = (3u8, U256::max_value(), U256::max_value()).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::max_value()); + + // Edge case + let input = (2u8, U256::from(255).to_big_endian()).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::from(65280)); + + // Edge case + let received = builder::bare_call(addr).data(vec![1]).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + + // OOB case + let input = (42u8).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + + // No calldata should return the zero value + let received = builder::bare_call(addr).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + }); +} + +#[test] +fn return_data_api_works() { + let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); + let (code_return_with_data, hash_return_with_data) = + compile_module("return_with_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Upload the io echoing fixture for later use + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code_return_with_data, + deposit_limit::(), + )); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code_return_data_api)) + .build_and_unwrap_contract(); + + // Call the contract: It will issue calls and deploys, asserting on + assert_ok!(builder::call(addr) + .value(10 * 1024) + .data(hash_return_with_data.encode()) + .build()); + }); +} + +#[test] +fn immutable_data_works() { + let (code, _) = compile_module("immutable_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let data = [0xfe; 8]; + + // Create fixture: Constructor sets the immtuable data + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .data(data.to_vec()) + .build_and_unwrap_contract(); + + let contract = get_contract(&addr); + let account = ::AddressMapper::to_account_id(&addr); + let actual_deposit = + get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account); + + assert_eq!(contract.immutable_data_len(), data.len() as u32); + + // Storing immmutable data charges storage deposit; verify it explicitly. + assert_eq!(actual_deposit, contract_base_deposit(&addr)); + + // make sure it is also recorded in the base deposit + assert_eq!( + get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account), + contract.storage_base_deposit(), + ); + + // Call the contract: Asserts the input to equal the immutable data + assert_ok!(builder::call(addr).data(data.to_vec()).build()); + }); +} + +#[test] +fn sbrk_cannot_be_deployed() { + let (code, _) = compile_module("sbrk").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code.clone(), + deposit_limit::(), + ), + >::InvalidInstruction + ); + + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::InvalidInstruction + ); + }); +} + +#[test] +fn overweight_basic_block_cannot_be_deployed() { + let (code, _) = compile_module("basic_block").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code.clone(), + deposit_limit::(), + ), + >::BasicBlockTooLarge + ); + + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::BasicBlockTooLarge + ); + }); +} + +#[test] +fn origin_api_works() { + let (code, _) = compile_module("origin").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: Asserts the origin API to work as expected + assert_ok!(builder::call(addr).build()); + }); +} + +#[test] +fn code_hash_works() { + use crate::precompiles::{Precompile, EVM_REVERT}; + use precompiles::NoInfo; + + let builtin_precompile = H160(NoInfo::::MATCHER.base_address()); + let primitive_precompile = H160::from_low_u64_be(1); + + let (code_hash_code, self_code_hash) = compile_module("code_hash").unwrap(); + let (dummy_code, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code_hash_code)).build_and_unwrap_contract(); + let Contract { addr: dummy_addr, .. } = + builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); + + // code hash of dummy contract + assert_ok!(builder::call(addr).data((dummy_addr, code_hash).encode()).build()); + // code hash of itself + assert_ok!(builder::call(addr).data((addr, self_code_hash).encode()).build()); + // code hash of primitive pre-compile (exist but have no bytecode) + assert_ok!(builder::call(addr) + .data((primitive_precompile, crate::exec::EMPTY_CODE_HASH).encode()) + .build()); + // code hash of normal pre-compile (do have a bytecode) + assert_ok!(builder::call(addr) + .data((builtin_precompile, sp_io::hashing::keccak_256(&EVM_REVERT)).encode()) + .build()); + + // EOA doesn't exists + assert_err!( + builder::bare_call(addr) + .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) + .build() + .result, + Error::::ContractTrapped + ); + // non-existing will return zero + assert_ok!(builder::call(addr).data((BOB_ADDR, H256::zero()).encode()).build()); + + // create EOA + let _ = ::Currency::set_balance( + &::AddressMapper::to_account_id(&BOB_ADDR), + 1_000_000, + ); + + // EOA returns empty code hash + assert_ok!(builder::call(addr) + .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) + .build()); + }); +} + +#[test] +fn code_size_works() { + let (tester_code, _) = compile_module("extcodesize").unwrap(); + let tester_code_len = tester_code.len() as u64; + + let (dummy_code, _) = compile_module("dummy").unwrap(); + let dummy_code_len = dummy_code.len() as u64; + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr: tester_addr, .. } = + builder::bare_instantiate(Code::Upload(tester_code)).build_and_unwrap_contract(); + let Contract { addr: dummy_addr, .. } = + builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); + + // code size of another contract address + assert_ok!(builder::call(tester_addr).data((dummy_addr, dummy_code_len).encode()).build()); + + // code size of own contract address + assert_ok!(builder::call(tester_addr) + .data((tester_addr, tester_code_len).encode()) + .build()); + + // code size of non contract accounts + assert_ok!(builder::call(tester_addr).data(([8u8; 20], 0u64).encode()).build()); + }); +} + +#[test] +fn origin_must_be_mapped() { + let (code, hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + ::Currency::set_balance(&EVE, 1_000_000); + + let eve = RuntimeOrigin::signed(EVE); + + // alice can instantiate as she doesn't need a mapping + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // without a mapping eve can neither call nor instantiate + assert_err!( + builder::bare_call(addr).origin(eve.clone()).build().result, + >::AccountUnmapped + ); + assert_err!( + builder::bare_instantiate(Code::Existing(hash)) + .origin(eve.clone()) + .build() + .result, + >::AccountUnmapped + ); + + // after mapping eve is usable as an origin + >::map_account(eve.clone()).unwrap(); + assert_ok!(builder::bare_call(addr).origin(eve.clone()).build().result); + assert_ok!(builder::bare_instantiate(Code::Existing(hash)).origin(eve).build().result); + }); +} + +#[test] +fn mapped_address_works() { + let (code, _) = compile_module("terminate_and_send_to_argument").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + // without a mapping everything will be send to the fallback account + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); + builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); + + // after mapping it will be sent to the real eve account + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + // need some balance to pay for the map deposit + ::Currency::set_balance(&EVE, 1_000); + >::map_account(RuntimeOrigin::signed(EVE)).unwrap(); + builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); + assert_eq!(::Currency::total_balance(&EVE), 1_100); + }); +} + +#[test] +fn recovery_works() { + let (code, _) = compile_module("terminate_and_send_to_argument").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + // eve puts her AccountId20 as argument to terminate but forgot to register + // her AccountId32 first so now the funds are trapped in her fallback account + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract(); + assert_eq!(::Currency::total_balance(&EVE), 0); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); + builder::bare_call(addr).data(EVE_ADDR.encode()).build_and_unwrap_result(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); + assert_eq!(::Currency::total_balance(&EVE), 0); + + let call = RuntimeCall::Balances(pallet_balances::Call::transfer_all { + dest: EVE, + keep_alive: false, + }); + + // she now uses the recovery function to move all funds from the fallback + // account to her real account + >::dispatch_as_fallback_account(RuntimeOrigin::signed(EVE), Box::new(call)) + .unwrap(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); + assert_eq!(::Currency::total_balance(&EVE), 100); + }); +} + +#[test] +fn skip_transfer_works() { + let (code_caller, _) = compile_module("call").unwrap(); + let (code, _) = compile_module("store_call").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + ::Currency::set_balance(&BOB, 0); + + // when gas is some (transfers enabled): bob has no money: fail + assert_err!( + Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + input: code.clone().into(), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + ), + EthTransactError::Message(format!( + "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" + )) + ); + + // no gas specified (all transfers are skipped): even without money bob can deploy + assert_ok!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + input: code.clone().into(), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + )); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(code_caller)).build_and_unwrap_contract(); + + // call directly: fails with enabled transfers + assert_err!( + Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(addr), + input: 0u32.encode().into(), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + ), + EthTransactError::Message(format!( + "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" + )) + ); + + // fails to call through other contract + // we didn't roll back the storage changes done by the previous + // call. So the item already exists. We simply increase the size of + // the storage item to incur some deposits (which bob can't pay). + assert!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: (1u32, &addr).encode().into(), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + ) + .is_err(),); + + // works when no gas is specified (skip transfer) + assert_ok!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(addr), + input: 2u32.encode().into(), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + )); + + // call through contract works when transfers are skipped + assert_ok!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: (3u32, &addr).encode().into(), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + )); + + // works with transfers enabled if we don't incur a storage cost + // we shrink the item so its actually a refund + assert_ok!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: (2u32, &addr).encode().into(), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + )); + + // fails when trying to increase the storage item size + assert!(Pallet::::dry_run_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: (3u32, &addr).encode().into(), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_, _| 0u64, + ) + .is_err()); + }); +} + +#[test] +fn gas_limit_api_works() { + let (code, _) = compile_module("gas_limit").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the gas limit API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!( + u64::from_le_bytes(received.data[..].try_into().unwrap()), + ::BlockWeights::get().max_block.ref_time() + ); + }); +} + +#[test] +fn unknown_syscall_rejected() { + let (code, _) = compile_module("unknown_syscall").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::CodeRejected, + ) + }); +} + +#[test] +fn unstable_interface_rejected() { + let (code, _) = compile_module("unstable_interface").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + Test::set_unstable_interface(false); + assert_err!( + builder::bare_instantiate(Code::Upload(code.clone())).build().result, + >::CodeRejected, + ); + + Test::set_unstable_interface(true); + assert_ok!(builder::bare_instantiate(Code::Upload(code)).build().result); + }); +} + +#[test] +fn tracing_works_for_transfers() { + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000); + let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); + trace(&mut tracer, || { + builder::bare_call(BOB_ADDR).evm_value(10.into()).build_and_unwrap_result(); + }); + + let trace = tracer.collect_trace(); + assert_eq!( + trace, + Some(CallTrace { + from: ALICE_ADDR, + to: BOB_ADDR, + value: Some(U256::from(10)), + call_type: CallType::Call, + ..Default::default() + }) + ) + }); +} + +#[test] +fn call_tracing_works() { + use crate::evm::*; + use CallType::*; + let (code, _code_hash) = compile_module("tracing").unwrap(); + let (binary_callee, _) = compile_module("tracing_callee").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000); + + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(binary_callee)).build_and_unwrap_contract(); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).evm_value(10_000_000.into()).build_and_unwrap_contract(); + + + let tracer_configs = vec![ + CallTracerConfig{ with_logs: false, only_top_call: false}, + CallTracerConfig{ with_logs: false, only_top_call: false}, + CallTracerConfig{ with_logs: false, only_top_call: true}, + ]; + + // Verify that the first trace report the same weight reported by bare_call + // TODO: fix tracing ( https://github.com/paritytech/polkadot-sdk/issues/8362 ) + /* + let mut tracer = CallTracer::new(false, |w| w); + let gas_used = trace(&mut tracer, || { + builder::bare_call(addr).data((3u32, addr_callee).encode()).build().gas_consumed + }); + let trace = tracer.collect_trace().unwrap(); + assert_eq!(&trace.gas_used, &gas_used); + */ + + // Discarding gas usage, check that traces reported are correct + for config in tracer_configs { + let logs = if config.with_logs { + vec![ + CallLog { + address: addr, + topics: Default::default(), + data: b"before".to_vec().into(), + position: 0, + }, + CallLog { + address: addr, + topics: Default::default(), + data: b"after".to_vec().into(), + position: 1, + }, + ] + } else { + vec![] + }; + + let calls = if config.only_top_call { + vec![] + } else { + vec![ + CallTrace { + from: addr, + to: addr_callee, + input: 2u32.encode().into(), + output: hex_literal::hex!( + "08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a546869732066756e6374696f6e20616c77617973206661696c73000000000000" + ).to_vec().into(), + revert_reason: Some("revert: This function always fails".to_string()), + error: Some("execution reverted".to_string()), + call_type: Call, + value: Some(U256::from(0)), + ..Default::default() + }, + CallTrace { + from: addr, + to: addr, + input: (2u32, addr_callee).encode().into(), + call_type: Call, + logs: logs.clone(), + value: Some(U256::from(0)), + calls: vec![ + CallTrace { + from: addr, + to: addr_callee, + input: 1u32.encode().into(), + output: Default::default(), + error: Some("ContractTrapped".to_string()), + call_type: Call, + value: Some(U256::from(0)), + ..Default::default() + }, + CallTrace { + from: addr, + to: addr, + input: (1u32, addr_callee).encode().into(), + call_type: Call, + logs: logs.clone(), + value: Some(U256::from(0)), + calls: vec![ + CallTrace { + from: addr, + to: addr_callee, + input: 0u32.encode().into(), + output: 0u32.to_le_bytes().to_vec().into(), + call_type: Call, + value: Some(U256::from(0)), + ..Default::default() + }, + CallTrace { + from: addr, + to: addr, + input: (0u32, addr_callee).encode().into(), + call_type: Call, + value: Some(U256::from(0)), + calls: vec![ + CallTrace { + from: addr, + to: BOB_ADDR, + value: Some(U256::from(100)), + call_type: CallType::Call, + ..Default::default() + } + ], + ..Default::default() + }, + ], + ..Default::default() + }, + ], + ..Default::default() + }, + ] + }; + + let mut tracer = CallTracer::new(config, |_| U256::zero()); + trace(&mut tracer, || { + builder::bare_call(addr).data((3u32, addr_callee).encode()).build() + }); + + let trace = tracer.collect_trace(); + let expected_trace = CallTrace { + from: ALICE_ADDR, + to: addr, + input: (3u32, addr_callee).encode().into(), + call_type: Call, + logs: logs.clone(), + value: Some(U256::from(0)), + calls: calls, + ..Default::default() + }; + + assert_eq!( + trace, + expected_trace.into(), + ); + } + }); +} + +#[test] +fn create_call_tracing_works() { + use crate::evm::*; + let (code, code_hash) = compile_module("create2_with_value").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000); + + let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); + + let Contract { addr, .. } = trace(&mut tracer, || { + builder::bare_instantiate(Code::Upload(code.clone())) + .evm_value(100.into()) + .salt(None) + .build_and_unwrap_contract() + }); + + let call_trace = tracer.collect_trace().unwrap(); + assert_eq!( + call_trace, + CallTrace { + from: ALICE_ADDR, + to: addr, + value: Some(100.into()), + input: Bytes(code.clone()), + call_type: CallType::Create, + ..Default::default() + } + ); + + let mut tracer = CallTracer::new(Default::default(), |_| U256::zero()); + let data = b"garbage"; + let input = (code_hash, data).encode(); + trace(&mut tracer, || { + assert_ok!(builder::call(addr).data(input.clone()).build()); + }); + + let call_trace = tracer.collect_trace().unwrap(); + let child_addr = crate::address::create2(&addr, &code, data, &[1u8; 32]); + + assert_eq!( + call_trace, + CallTrace { + from: ALICE_ADDR, + to: addr, + value: Some(0.into()), + input: input.clone().into(), + calls: vec![CallTrace { + from: addr, + input: input.clone().into(), + to: child_addr, + value: Some(0.into()), + call_type: CallType::Create2, + ..Default::default() + },], + ..Default::default() + } + ); + }); +} + +#[test] +fn prestate_tracing_works() { + use crate::evm::*; + use alloc::collections::BTreeMap; + + let (dummy_code, _) = compile_module("dummy").unwrap(); + let (code, _) = compile_module("tracing").unwrap(); + let (callee_code, _) = compile_module("tracing_callee").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000); + + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(callee_code.clone())) + .build_and_unwrap_contract(); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) + .native_value(10) + .build_and_unwrap_contract(); + + // redact balance so that tests are resilient to weight changes + let alice_redacted_balance = Some(U256::from(1)); + + let test_cases: Vec<(Box, _, _)> = vec![ + ( + Box::new(|| { + builder::bare_call(addr) + .data((3u32, addr_callee).encode()) + .build_and_unwrap_result(); + }), + PrestateTracerConfig { + diff_mode: false, + disable_storage: false, + disable_code: false, + }, + PrestateTrace::Prestate(BTreeMap::from([ + ( + ALICE_ADDR, + PrestateTraceInfo { + balance: alice_redacted_balance, + nonce: Some(2), + ..Default::default() + }, + ), + ( + BOB_ADDR, + PrestateTraceInfo { balance: Some(U256::from(0u64)), ..Default::default() }, + ), + ( + addr_callee, + PrestateTraceInfo { + balance: Some(U256::from(0u64)), + code: Some(Bytes(callee_code.clone())), + nonce: Some(1), + ..Default::default() + }, + ), + ( + addr, + PrestateTraceInfo { + balance: Some(U256::from(10_000_000u64)), + code: Some(Bytes(code.clone())), + nonce: Some(1), + ..Default::default() + }, + ), + ])), + ), + ( + Box::new(|| { + builder::bare_call(addr) + .data((3u32, addr_callee).encode()) + .build_and_unwrap_result(); + }), + PrestateTracerConfig { + diff_mode: true, + disable_storage: false, + disable_code: false, + }, + PrestateTrace::DiffMode { + pre: BTreeMap::from([ + ( + BOB_ADDR, + PrestateTraceInfo { + balance: Some(U256::from(100u64)), + ..Default::default() + }, + ), + ( + addr, + PrestateTraceInfo { + balance: Some(U256::from(9_999_900u64)), + code: Some(Bytes(code.clone())), + nonce: Some(1), + ..Default::default() + }, + ), + ]), + post: BTreeMap::from([ + ( + BOB_ADDR, + PrestateTraceInfo { + balance: Some(U256::from(200u64)), + ..Default::default() + }, + ), + ( + addr, + PrestateTraceInfo { + balance: Some(U256::from(9_999_800u64)), + ..Default::default() + }, + ), + ]), + }, + ), + ( + Box::new(|| { + builder::bare_instantiate(Code::Upload(dummy_code.clone())) + .salt(None) + .build_and_unwrap_result(); + }), + PrestateTracerConfig { + diff_mode: true, + disable_storage: false, + disable_code: false, + }, + PrestateTrace::DiffMode { + pre: BTreeMap::from([( + ALICE_ADDR, + PrestateTraceInfo { + balance: alice_redacted_balance, + nonce: Some(2), + ..Default::default() + }, + )]), + post: BTreeMap::from([ + ( + ALICE_ADDR, + PrestateTraceInfo { + balance: alice_redacted_balance, + nonce: Some(3), + ..Default::default() + }, + ), + ( + create1(&ALICE_ADDR, 1), + PrestateTraceInfo { + code: Some(dummy_code.clone().into()), + balance: Some(U256::from(0)), + nonce: Some(1), + ..Default::default() + }, + ), + ]), + }, + ), + ]; + + for (exec_call, config, expected_trace) in test_cases.into_iter() { + let mut tracer = PrestateTracer::::new(config); + trace(&mut tracer, || { + exec_call(); + }); + + let mut trace = tracer.collect_trace(); + + // redact alice balance + match trace { + PrestateTrace::DiffMode { ref mut pre, ref mut post } => { + pre.get_mut(&ALICE_ADDR).map(|info| { + info.balance = alice_redacted_balance; + }); + post.get_mut(&ALICE_ADDR).map(|info| { + info.balance = alice_redacted_balance; + }); + }, + PrestateTrace::Prestate(ref mut pre) => { + pre.get_mut(&ALICE_ADDR).map(|info| { + info.balance = alice_redacted_balance; + }); + }, + } + + assert_eq!(trace, expected_trace); + } + }); +} + +#[test] +fn unknown_precompiles_revert() { + let (code, _code_hash) = compile_module("read_only_call").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let cases: Vec<(H160, Box)> = vec![( + H160::from_low_u64_be(0x0a), + Box::new(|result| { + assert_err!(result, >::UnsupportedPrecompileAddress); + }), + )]; + + for (callee_addr, assert_result) in cases { + let result = + builder::bare_call(addr).data((callee_addr, [0u8; 0]).encode()).build().result; + assert_result(result); + } + }); +} + +#[test] +fn pure_precompile_works() { + use hex_literal::hex; + + let cases = vec![ + ( + "ECRecover", + H160::from_low_u64_be(1), + hex!("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").to_vec(), + hex!("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").to_vec(), + ), + ( + "Sha256", + H160::from_low_u64_be(2), + hex!("ec07171c4f0f0e2b").to_vec(), + hex!("d0591ea667763c69a5f5a3bae657368ea63318b2c9c8349cccaf507e3cbd7c7a").to_vec(), + ), + ( + "Ripemd160", + H160::from_low_u64_be(3), + hex!("ec07171c4f0f0e2b").to_vec(), + hex!("000000000000000000000000a9c5ebaf7589fd8acfd542c3a008956de84fbeb7").to_vec(), + ), + ( + "Identity", + H160::from_low_u64_be(4), + [42u8; 128].to_vec(), + [42u8; 128].to_vec(), + ), + ( + "Modexp", + H160::from_low_u64_be(5), + hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f").to_vec(), + hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec(), + ), + ( + "Bn128Add", + H160::from_low_u64_be(6), + hex!("18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7").to_vec(), + hex!("2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915").to_vec(), + ), + ( + "Bn128Mul", + H160::from_low_u64_be(7), + hex!("2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2").to_vec(), + hex!("070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc").to_vec(), + ), + ( + "Bn128Pairing", + H160::from_low_u64_be(8), + hex!("1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").to_vec(), + hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec(), + ), + ( + "Blake2F", + H160::from_low_u64_be(9), + hex!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001").to_vec(), + hex!("08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b").to_vec(), + ), + ]; + + for (description, precompile_addr, input, output) in cases { + let (code, _code_hash) = compile_module("call_and_return").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(1_000) + .build_and_unwrap_contract(); + + let result = builder::bare_call(addr) + .data( + (&precompile_addr, 100u64) + .encode() + .into_iter() + .chain(input) + .collect::>(), + ) + .build_and_unwrap_result(); + + assert_eq!( + Pallet::::evm_balance(&precompile_addr), + U256::from(100), + "{description}: unexpected balance" + ); + assert_eq!( + alloy_core::hex::encode(result.data), + alloy_core::hex::encode(output), + "{description} Unexpected output for precompile: {precompile_addr:?}", + ); + assert_eq!(result.flags, ReturnFlags::empty()); + }); + } +} + +#[test] +fn precompiles_work() { + use crate::precompiles::Precompile; + use alloy_core::sol_types::{Panic, PanicKind, Revert, SolError, SolInterface, SolValue}; + use precompiles::{INoInfo, NoInfo}; + + let precompile_addr = H160(NoInfo::::MATCHER.base_address()); + + let cases = vec![ + ( + INoInfo::INoInfoCalls::identity(INoInfo::identityCall { number: 42u64.into() }) + .abi_encode(), + 42u64.abi_encode(), + RuntimeReturnCode::Success, + ), + ( + INoInfo::INoInfoCalls::reverts(INoInfo::revertsCall { error: "panic".to_string() }) + .abi_encode(), + Revert::from("panic").abi_encode(), + RuntimeReturnCode::CalleeReverted, + ), + ( + INoInfo::INoInfoCalls::panics(INoInfo::panicsCall {}).abi_encode(), + Panic::from(PanicKind::Assert).abi_encode(), + RuntimeReturnCode::CalleeReverted, + ), + ( + INoInfo::INoInfoCalls::errors(INoInfo::errorsCall {}).abi_encode(), + Vec::new(), + RuntimeReturnCode::CalleeTrapped, + ), + // passing non decodeable input reverts with solidity panic + ( + b"invalid".to_vec(), + Panic::from(PanicKind::ResourceError).abi_encode(), + RuntimeReturnCode::CalleeReverted, + ), + ( + INoInfo::INoInfoCalls::passData(INoInfo::passDataCall { + inputLen: limits::CALLDATA_BYTES, + }) + .abi_encode(), + Vec::new(), + RuntimeReturnCode::Success, + ), + ( + INoInfo::INoInfoCalls::passData(INoInfo::passDataCall { + inputLen: limits::CALLDATA_BYTES + 1, + }) + .abi_encode(), + Vec::new(), + RuntimeReturnCode::CalleeTrapped, + ), + ( + INoInfo::INoInfoCalls::returnData(INoInfo::returnDataCall { + returnLen: limits::CALLDATA_BYTES - 4, + }) + .abi_encode(), + vec![42u8; limits::CALLDATA_BYTES as usize - 4], + RuntimeReturnCode::Success, + ), + ( + INoInfo::INoInfoCalls::returnData(INoInfo::returnDataCall { + returnLen: limits::CALLDATA_BYTES + 1, + }) + .abi_encode(), + vec![], + RuntimeReturnCode::CalleeTrapped, + ), + ]; + + for (input, output, error_code) in cases { + let (code, _code_hash) = compile_module("call_and_returncode").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let id = ::AddressMapper::to_account_id(&precompile_addr); + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(1000) + .build_and_unwrap_contract(); + + let result = builder::bare_call(addr) + .data( + (&precompile_addr, 0u64).encode().into_iter().chain(input).collect::>(), + ) + .build_and_unwrap_result(); + + // no account or contract info should be created for a NoInfo pre-compile + assert!(get_contract_checked(&precompile_addr).is_none()); + assert!(!System::account_exists(&id)); + assert_eq!(Pallet::::evm_balance(&precompile_addr), U256::zero()); + + assert_eq!(result.flags, ReturnFlags::empty()); + assert_eq!(u32::from_le_bytes(result.data[..4].try_into().unwrap()), error_code as u32); + assert_eq!( + &result.data[4..], + &output, + "Unexpected output for precompile: {precompile_addr:?}", + ); + }); + } +} + +#[test] +fn precompiles_with_info_creates_contract() { + use crate::precompiles::Precompile; + use alloy_core::sol_types::SolInterface; + use precompiles::{IWithInfo, WithInfo}; + + let precompile_addr = H160(WithInfo::::MATCHER.base_address()); + + let cases = vec![( + IWithInfo::IWithInfoCalls::dummy(IWithInfo::dummyCall {}).abi_encode(), + Vec::::new(), + RuntimeReturnCode::Success, + )]; + + for (input, output, error_code) in cases { + let (code, _code_hash) = compile_module("call_and_returncode").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let id = ::AddressMapper::to_account_id(&precompile_addr); + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(1000) + .build_and_unwrap_contract(); + + let result = builder::bare_call(addr) + .data( + (&precompile_addr, 0u64).encode().into_iter().chain(input).collect::>(), + ) + .build_and_unwrap_result(); + + // a pre-compile with contract info should create an account on first call + assert!(get_contract_checked(&precompile_addr).is_some()); + assert!(System::account_exists(&id)); + assert_eq!(Pallet::::evm_balance(&precompile_addr), U256::from(0)); + + assert_eq!(result.flags, ReturnFlags::empty()); + assert_eq!(u32::from_le_bytes(result.data[..4].try_into().unwrap()), error_code as u32); + assert_eq!( + &result.data[4..], + &output, + "Unexpected output for precompile: {precompile_addr:?}", + ); + }); + } +} + +#[test] +fn bump_nonce_once_works() { + let (code, hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + frame_system::Account::::mutate(&ALICE, |account| account.nonce = 1); + + let _ = ::Currency::set_balance(&BOB, 1_000_000); + frame_system::Account::::mutate(&BOB, |account| account.nonce = 1); + + builder::bare_instantiate(Code::Upload(code.clone())) + .origin(RuntimeOrigin::signed(ALICE)) + .bump_nonce(BumpNonce::Yes) + .salt(None) + .build_and_unwrap_result(); + assert_eq!(System::account_nonce(&ALICE), 2); + + // instantiate again is ok + let result = builder::bare_instantiate(Code::Existing(hash)) + .origin(RuntimeOrigin::signed(ALICE)) + .bump_nonce(BumpNonce::Yes) + .salt(None) + .build() + .result; + assert!(result.is_ok()); + + builder::bare_instantiate(Code::Upload(code.clone())) + .origin(RuntimeOrigin::signed(BOB)) + .bump_nonce(BumpNonce::No) + .salt(None) + .build_and_unwrap_result(); + assert_eq!(System::account_nonce(&BOB), 1); + + // instantiate again should fail + let err = builder::bare_instantiate(Code::Upload(code)) + .origin(RuntimeOrigin::signed(BOB)) + .bump_nonce(BumpNonce::No) + .salt(None) + .build() + .result + .unwrap_err(); + + assert_eq!(err, >::DuplicateContract.into()); + }); +} + +#[test] +fn code_size_for_precompiles_works() { + use crate::precompiles::Precompile; + use precompiles::NoInfo; + + let builtin_precompile = H160(NoInfo::::MATCHER.base_address()); + let primitive_precompile = H160::from_low_u64_be(1); + + let (code, _code_hash) = compile_module("extcodesize").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .native_value(1000) + .build_and_unwrap_contract(); + + // the primitive pre-compiles return 0 code size on eth + builder::bare_call(addr) + .data((&primitive_precompile, 0u64).encode()) + .build_and_unwrap_result(); + + // other precompiles should return the minimal evm revert code + builder::bare_call(addr) + .data((&builtin_precompile, 5u64).encode()) + .build_and_unwrap_result(); + }); +} + +#[test] +fn call_data_limit_is_enforced_subcalls() { + let (code, _code_hash) = compile_module("call_with_input_size").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let cases: Vec<(u32, Box)> = vec![ + ( + 0_u32, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + 1_u32, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + limits::CALLDATA_BYTES, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + limits::CALLDATA_BYTES + 1, + Box::new(|result| { + assert_err!(result, >::CallDataTooLarge); + }), + ), + ]; + + for (callee_input_size, assert_result) in cases { + let result = builder::bare_call(addr).data(callee_input_size.encode()).build().result; + assert_result(result); + } + }); +} + +#[test] +fn call_data_limit_is_enforced_root_call() { + let (code, _code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let cases: Vec<(H160, u32, Box)> = vec![ + ( + addr, + 0_u32, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + addr, + 1_u32, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + addr, + limits::CALLDATA_BYTES, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + addr, + limits::CALLDATA_BYTES + 1, + Box::new(|result| { + assert_err!(result, >::CallDataTooLarge); + }), + ), + ( + // limit is not enforced when tx calls EOA + BOB_ADDR, + limits::CALLDATA_BYTES + 1, + Box::new(|result| { + assert_ok!(result); + }), + ), + ]; + + for (addr, callee_input_size, assert_result) in cases { + let result = builder::bare_call(addr) + .data(vec![42; callee_input_size as usize]) + .build() + .result; + assert_result(result); + } + }); +} + +#[test] +fn return_data_limit_is_enforced() { + let (code, _code_hash) = compile_module("return_sized").unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let cases: Vec<(u32, Box)> = vec![ + ( + 1_u32, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + limits::CALLDATA_BYTES, + Box::new(|result| { + assert_ok!(result); + }), + ), + ( + limits::CALLDATA_BYTES + 1, + Box::new(|result| { + assert_err!(result, >::ReturnDataTooLarge); + }), + ), + ]; + + for (return_size, assert_result) in cases { + let result = builder::bare_call(addr).data(return_size.encode()).build().result; + assert_result(result); + } + }); +} diff --git a/substrate/frame/revive/src/vm/mod.rs b/substrate/frame/revive/src/vm/mod.rs index ced372c320ba1..3c65cbbfccab3 100644 --- a/substrate/frame/revive/src/vm/mod.rs +++ b/substrate/frame/revive/src/vm/mod.rs @@ -18,23 +18,16 @@ //! This module provides a means for executing contracts //! represented in vm bytecode. -mod runtime; +pub mod pvm; +mod runtime_costs; -#[cfg(doc)] -pub use crate::vm::runtime::SyscallDoc; - -#[cfg(feature = "runtime-benchmarks")] -pub use crate::vm::runtime::{ReturnData, TrapReason}; - -pub use crate::vm::runtime::{Runtime, RuntimeCosts}; +pub use runtime_costs::RuntimeCosts; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::{GasMeter, Token}, - limits, - storage::meter::Diff, weights::WeightInfo, - AccountIdOf, BadOrigin, BalanceOf, CodeInfoOf, CodeVec, Config, Error, ExecError, HoldReason, + AccountIdOf, BadOrigin, BalanceOf, CodeInfoOf, CodeVec, Config, Error, HoldReason, PristineCode, Weight, LOG_TARGET, }; use alloc::vec::Vec; @@ -44,7 +37,7 @@ use frame_support::{ ensure, traits::{fungible::MutateHold, tokens::Precision::BestEffort}, }; -use sp_core::{Get, H256, U256}; +use sp_core::{H256, U256}; use sp_runtime::DispatchError; /// Validated Vm module ready for execution. @@ -132,29 +125,6 @@ impl ContractBlob where BalanceOf: Into + TryFrom, { - /// We only check for size and nothing else when the code is uploaded. - pub fn from_code(code: Vec, owner: AccountIdOf) -> Result { - // We do validation only when new code is deployed. This allows us to increase - // the limits later without affecting already deployed code. - let available_syscalls = runtime::list_syscalls(T::UnsafeUnstableInterface::get()); - let code = limits::code::enforce::(code, available_syscalls)?; - - let code_len = code.len() as u32; - let bytes_added = code_len.saturating_add(>::max_encoded_len() as u32); - let deposit = Diff { bytes_added, items_added: 2, ..Default::default() } - .update_contract::(None) - .charge_or_zero(); - let code_info = CodeInfo { - owner, - deposit, - refcount: 0, - code_len, - behaviour_version: Default::default(), - }; - let code_hash = H256(sp_io::hashing::keccak_256(&code)); - Ok(ContractBlob { code, code_info, code_hash }) - } - /// Remove the code from storage and refund the deposit to its owner. /// /// Applies all necessary checks before removing the code. @@ -284,119 +254,6 @@ impl CodeInfo { } } -pub struct PreparedCall<'a, E: Ext> { - module: polkavm::Module, - instance: polkavm::RawInstance, - runtime: Runtime<'a, E, polkavm::RawInstance>, -} - -impl<'a, E: Ext> PreparedCall<'a, E> -where - BalanceOf: Into, - BalanceOf: TryFrom, -{ - pub fn call(mut self) -> ExecResult { - let exec_result = loop { - let interrupt = self.instance.run(); - if let Some(exec_result) = - self.runtime.handle_interrupt(interrupt, &self.module, &mut self.instance) - { - break exec_result - } - }; - let _ = self.runtime.ext().gas_meter_mut().sync_from_executor(self.instance.gas())?; - exec_result - } - - /// The guest memory address at which the aux data is located. - #[cfg(feature = "runtime-benchmarks")] - pub fn aux_data_base(&self) -> u32 { - self.instance.module().memory_map().aux_data_address() - } - - /// Copies `data` to the aux data at address `offset`. - /// - /// It sets `a0` to the beginning of data inside the aux data. - /// It sets `a1` to the value passed. - /// - /// Only used in benchmarking so far. - #[cfg(feature = "runtime-benchmarks")] - pub fn setup_aux_data(&mut self, data: &[u8], offset: u32, a1: u64) -> DispatchResult { - let a0 = self.aux_data_base().saturating_add(offset); - self.instance.write_memory(a0, data).map_err(|err| { - log::debug!(target: LOG_TARGET, "failed to write aux data: {err:?}"); - Error::::CodeRejected - })?; - self.instance.set_reg(polkavm::Reg::A0, a0.into()); - self.instance.set_reg(polkavm::Reg::A1, a1); - Ok(()) - } -} - -impl ContractBlob { - /// Compile and instantiate contract. - /// - /// `aux_data_size` is only used for runtime benchmarks. Real contracts - /// don't make use of this buffer. Hence this should not be set to anything - /// other than `0` when not used for benchmarking. - pub fn prepare_call>( - self, - mut runtime: Runtime, - entry_point: ExportedFunction, - aux_data_size: u32, - ) -> Result, ExecError> { - let mut config = polkavm::Config::default(); - config.set_backend(Some(polkavm::BackendKind::Interpreter)); - config.set_cache_enabled(false); - #[cfg(feature = "std")] - if std::env::var_os("REVIVE_USE_COMPILER").is_some() { - log::warn!(target: LOG_TARGET, "Using PolkaVM compiler backend because env var REVIVE_USE_COMPILER is set"); - config.set_backend(Some(polkavm::BackendKind::Compiler)); - } - let engine = polkavm::Engine::new(&config).expect( - "on-chain (no_std) use of interpreter is hard coded. - interpreter is available on all platforms; qed", - ); - - let mut module_config = polkavm::ModuleConfig::new(); - module_config.set_page_size(limits::PAGE_SIZE); - module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync)); - module_config.set_allow_sbrk(false); - module_config.set_aux_data_size(aux_data_size); - let module = polkavm::Module::new(&engine, &module_config, self.code.into_inner().into()) - .map_err(|err| { - log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}"); - Error::::CodeRejected - })?; - - let entry_program_counter = module - .exports() - .find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes()) - .ok_or_else(|| >::CodeRejected)? - .program_counter(); - - let gas_limit_polkavm: polkavm::Gas = runtime.ext().gas_meter_mut().engine_fuel_left()?; - - let mut instance = module.instantiate().map_err(|err| { - log::debug!(target: LOG_TARGET, "failed to instantiate polkavm module: {err:?}"); - Error::::CodeRejected - })?; - - instance.set_gas(gas_limit_polkavm); - instance - .set_interpreter_cache_size_limit(Some(polkavm::SetCacheSizeLimitArgs { - max_block_size: limits::code::BASIC_BLOCK_SIZE, - max_cache_size_bytes: limits::code::INTERPRETER_CACHE_BYTES - .try_into() - .map_err(|_| Error::::CodeRejected)?, - })) - .map_err(|_| Error::::CodeRejected)?; - instance.prepare_call_untyped(entry_program_counter, &[]); - - Ok(PreparedCall { module, instance, runtime }) - } -} - impl Executable for ContractBlob where BalanceOf: Into + TryFrom, @@ -414,8 +271,13 @@ where function: ExportedFunction, input_data: Vec, ) -> ExecResult { - let prepared_call = self.prepare_call(Runtime::new(ext, input_data), function, 0)?; - prepared_call.call() + if self.is_pvm() { + let prepared_call = + self.prepare_call(pvm::Runtime::new(ext, input_data), function, 0)?; + prepared_call.call() + } else { + Err(Error::::CodeRejected.into()) + } } fn code(&self) -> &[u8] { diff --git a/substrate/frame/revive/src/vm/pvm.rs b/substrate/frame/revive/src/vm/pvm.rs new file mode 100644 index 0000000000000..b0a2ed8264b24 --- /dev/null +++ b/substrate/frame/revive/src/vm/pvm.rs @@ -0,0 +1,960 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Environment definition of the vm smart-contract runtime. + +pub mod env; + +#[cfg(doc)] +pub use env::SyscallDoc; + +use crate::{ + evm::runtime::GAS_PRICE, + exec::{ExecError, ExecResult, Ext, Key}, + gas::ChargedAmount, + limits, + precompiles::{All as AllPrecompiles, Precompiles}, + primitives::ExecReturnValue, + BalanceOf, Config, Error, Pallet, RuntimeCosts, LOG_TARGET, SENTINEL, +}; +use alloc::{vec, vec::Vec}; +use codec::Encode; +use core::{fmt, marker::PhantomData, mem}; +use frame_support::{ensure, weights::Weight}; +use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags, StorageFlags}; +use sp_core::{H160, H256, U256}; +use sp_runtime::{DispatchError, RuntimeDebug}; + +/// Abstraction over the memory access within syscalls. +/// +/// The reason for this abstraction is that we run syscalls on the host machine when +/// benchmarking them. In that case we have direct access to the contract's memory. However, when +/// running within PolkaVM we need to resort to copying as we can't map the contracts memory into +/// the host (as of now). +pub trait Memory { + /// Read designated chunk from the sandbox memory into the supplied buffer. + /// + /// Returns `Err` if one of the following conditions occurs: + /// + /// - requested buffer is not within the bounds of the sandbox memory. + fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError>; + + /// Write the given buffer to the designated location in the sandbox memory. + /// + /// Returns `Err` if one of the following conditions occurs: + /// + /// - designated area is not within the bounds of the sandbox memory. + fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError>; + + /// Zero the designated location in the sandbox memory. + /// + /// Returns `Err` if one of the following conditions occurs: + /// + /// - designated area is not within the bounds of the sandbox memory. + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError>; + + /// This will reset all compilation artifacts of the currently executing instance. + /// + /// This is used before we call into a new contract to free up some memory. Doing + /// so we make sure that we only ever have to hold one compilation cache at a time + /// independtently of of our call stack depth. + fn reset_interpreter_cache(&mut self); + + /// Read designated chunk from the sandbox memory. + /// + /// Returns `Err` if one of the following conditions occurs: + /// + /// - requested buffer is not within the bounds of the sandbox memory. + fn read(&self, ptr: u32, len: u32) -> Result, DispatchError> { + let mut buf = vec![0u8; len as usize]; + self.read_into_buf(ptr, buf.as_mut_slice())?; + Ok(buf) + } + + /// Same as `read` but reads into a fixed size buffer. + fn read_array(&self, ptr: u32) -> Result<[u8; N], DispatchError> { + let mut buf = [0u8; N]; + self.read_into_buf(ptr, &mut buf)?; + Ok(buf) + } + + /// Read a `u32` from the sandbox memory. + fn read_u32(&self, ptr: u32) -> Result { + let buf: [u8; 4] = self.read_array(ptr)?; + Ok(u32::from_le_bytes(buf)) + } + + /// Read a `U256` from the sandbox memory. + fn read_u256(&self, ptr: u32) -> Result { + let buf: [u8; 32] = self.read_array(ptr)?; + Ok(U256::from_little_endian(&buf)) + } + + /// Read a `H160` from the sandbox memory. + fn read_h160(&self, ptr: u32) -> Result { + let mut buf = H160::default(); + self.read_into_buf(ptr, buf.as_bytes_mut())?; + Ok(buf) + } + + /// Read a `H256` from the sandbox memory. + fn read_h256(&self, ptr: u32) -> Result { + let mut code_hash = H256::default(); + self.read_into_buf(ptr, code_hash.as_bytes_mut())?; + Ok(code_hash) + } +} + +/// Allows syscalls access to the PolkaVM instance they are executing in. +/// +/// In case a contract is executing within PolkaVM its `memory` argument will also implement +/// this trait. The benchmarking implementation of syscalls will only require `Memory` +/// to be implemented. +pub trait PolkaVmInstance: Memory { + fn gas(&self) -> polkavm::Gas; + fn set_gas(&mut self, gas: polkavm::Gas); + fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64); + fn write_output(&mut self, output: u64); +} + +// Memory implementation used in benchmarking where guest memory is mapped into the host. +// +// Please note that we could optimize the `read_as_*` functions by decoding directly from +// memory without a copy. However, we don't do that because as it would change the behaviour +// of those functions: A `read_as` with a `len` larger than the actual type can succeed +// in the streaming implementation while it could fail with a segfault in the copy implementation. +#[cfg(feature = "runtime-benchmarks")] +impl Memory for [u8] { + fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { + let ptr = ptr as usize; + let bound_checked = + self.get(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; + buf.copy_from_slice(bound_checked); + Ok(()) + } + + fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { + let ptr = ptr as usize; + let bound_checked = + self.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; + bound_checked.copy_from_slice(buf); + Ok(()) + } + + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { + <[u8] as Memory>::write(self, ptr, &vec![0; len as usize]) + } + + fn reset_interpreter_cache(&mut self) {} +} + +impl Memory for polkavm::RawInstance { + fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { + self.read_memory_into(ptr, buf) + .map(|_| ()) + .map_err(|_| Error::::OutOfBounds.into()) + } + + fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { + self.write_memory(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) + } + + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { + self.zero_memory(ptr, len).map_err(|_| Error::::OutOfBounds.into()) + } + + fn reset_interpreter_cache(&mut self) { + self.reset_interpreter_cache(); + } +} + +impl PolkaVmInstance for polkavm::RawInstance { + fn gas(&self) -> polkavm::Gas { + self.gas() + } + + fn set_gas(&mut self, gas: polkavm::Gas) { + self.set_gas(gas) + } + + fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64) { + ( + self.reg(polkavm::Reg::A0), + self.reg(polkavm::Reg::A1), + self.reg(polkavm::Reg::A2), + self.reg(polkavm::Reg::A3), + self.reg(polkavm::Reg::A4), + self.reg(polkavm::Reg::A5), + ) + } + + fn write_output(&mut self, output: u64) { + self.set_reg(polkavm::Reg::A0, output); + } +} + +impl From<&ExecReturnValue> for ReturnErrorCode { + fn from(from: &ExecReturnValue) -> Self { + if from.flags.contains(ReturnFlags::REVERT) { + Self::CalleeReverted + } else { + Self::Success + } + } +} + +/// The data passed through when a contract uses `seal_return`. +#[derive(RuntimeDebug)] +pub struct ReturnData { + /// The flags as passed through by the contract. They are still unchecked and + /// will later be parsed into a `ReturnFlags` bitflags struct. + flags: u32, + /// The output buffer passed by the contract as return data. + data: Vec, +} + +/// Enumerates all possible reasons why a trap was generated. +/// +/// This is either used to supply the caller with more information about why an error +/// occurred (the SupervisorError variant). +/// The other case is where the trap does not constitute an error but rather was invoked +/// as a quick way to terminate the application (all other variants). +#[derive(RuntimeDebug)] +pub enum TrapReason { + /// The supervisor trapped the contract because of an error condition occurred during + /// execution in privileged code. + SupervisorError(DispatchError), + /// Signals that trap was generated in response to call `seal_return` host function. + Return(ReturnData), + /// Signals that a trap was generated in response to a successful call to the + /// `seal_terminate` host function. + Termination, +} + +impl> From for TrapReason { + fn from(from: T) -> Self { + Self::SupervisorError(from.into()) + } +} + +impl fmt::Display for TrapReason { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + Ok(()) + } +} + +/// Same as [`Runtime::charge_gas`]. +/// +/// We need this access as a macro because sometimes hiding the lifetimes behind +/// a function won't work out. +macro_rules! charge_gas { + ($runtime:expr, $costs:expr) => {{ + $runtime.ext.gas_meter_mut().charge($costs) + }}; +} + +/// The kind of call that should be performed. +enum CallType { + /// Execute another instantiated contract + Call { value_ptr: u32 }, + /// Execute another contract code in the context (storage, account ID, value) of the caller + /// contract + DelegateCall, +} + +impl CallType { + fn cost(&self) -> RuntimeCosts { + match self { + CallType::Call { .. } => RuntimeCosts::CallBase, + CallType::DelegateCall => RuntimeCosts::DelegateCallBase, + } + } +} + +/// This is only appropriate when writing out data of constant size that does not depend on user +/// input. In this case the costs for this copy was already charged as part of the token at +/// the beginning of the API entry point. +fn already_charged(_: u32) -> Option { + None +} + +/// Helper to extract two `u32` values from a given `u64` register. +fn extract_hi_lo(reg: u64) -> (u32, u32) { + ((reg >> 32) as u32, reg as u32) +} + +/// Provides storage variants to support standard and Etheruem compatible semantics. +enum StorageValue { + /// Indicates that the storage value should be read from a memory buffer. + /// - `ptr`: A pointer to the start of the data in sandbox memory. + /// - `len`: The length (in bytes) of the data. + Memory { ptr: u32, len: u32 }, + + /// Indicates that the storage value is provided inline as a fixed-size (256-bit) value. + /// This is used by set_storage_or_clear() to avoid double reads. + /// This variant is used to implement Ethereum SSTORE-like semantics. + Value(Vec), +} + +/// Controls the output behavior for storage reads, both when a key is found and when it is not. +enum StorageReadMode { + /// VariableOutput mode: if the key exists, the full stored value is returned + /// using the caller‑provided output length. + VariableOutput { output_len_ptr: u32 }, + /// Ethereum compatible(FixedOutput32) mode: always write a 32-byte value into the output + /// buffer. If the key is missing, write 32 bytes of zeros. + FixedOutput32, +} + +/// Can only be used for one call. +pub struct Runtime<'a, E: Ext, M: ?Sized> { + ext: &'a mut E, + input_data: Option>, + _phantom_data: PhantomData, +} + +impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { + pub fn new(ext: &'a mut E, input_data: Vec) -> Self { + Self { ext, input_data: Some(input_data), _phantom_data: Default::default() } + } + + /// Get a mutable reference to the inner `Ext`. + pub fn ext(&mut self) -> &mut E { + self.ext + } + + /// Charge the gas meter with the specified token. + /// + /// Returns `Err(HostError)` if there is not enough gas. + fn charge_gas(&mut self, costs: RuntimeCosts) -> Result { + charge_gas!(self, costs) + } + + /// Adjust a previously charged amount down to its actual amount. + /// + /// This is when a maximum a priori amount was charged and then should be partially + /// refunded to match the actual amount. + fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) { + self.ext.gas_meter_mut().adjust_gas(charged, actual_costs); + } + + /// Write the given buffer and its length to the designated locations in sandbox memory and + /// charge gas according to the token returned by `create_token`. + /// + /// `out_ptr` is the location in sandbox memory where `buf` should be written to. + /// `out_len_ptr` is an in-out location in sandbox memory. It is read to determine the + /// length of the buffer located at `out_ptr`. If that buffer is smaller than the actual + /// `buf.len()`, only what fits into that buffer is written to `out_ptr`. + /// The actual amount of bytes copied to `out_ptr` is written to `out_len_ptr`. + /// + /// If `out_ptr` is set to the sentinel value of `SENTINEL` and `allow_skip` is true the + /// operation is skipped and `Ok` is returned. This is supposed to help callers to make copying + /// output optional. For example to skip copying back the output buffer of an `seal_call` + /// when the caller is not interested in the result. + /// + /// `create_token` can optionally instruct this function to charge the gas meter with the token + /// it returns. `create_token` receives the variable amount of bytes that are about to be copied + /// by this function. + /// + /// In addition to the error conditions of `Memory::write` this functions returns + /// `Err` if the size of the buffer located at `out_ptr` is too small to fit `buf`. + pub fn write_sandbox_output( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + buf: &[u8], + allow_skip: bool, + create_token: impl FnOnce(u32) -> Option, + ) -> Result<(), DispatchError> { + if allow_skip && out_ptr == SENTINEL { + return Ok(()); + } + + let len = memory.read_u32(out_len_ptr)?; + let buf_len = len.min(buf.len() as u32); + + if let Some(costs) = create_token(buf_len) { + self.charge_gas(costs)?; + } + + memory.write(out_ptr, &buf[..buf_len as usize])?; + memory.write(out_len_ptr, &buf_len.encode()) + } + + /// Same as `write_sandbox_output` but for static size output. + pub fn write_fixed_sandbox_output( + &mut self, + memory: &mut M, + out_ptr: u32, + buf: &[u8], + allow_skip: bool, + create_token: impl FnOnce(u32) -> Option, + ) -> Result<(), DispatchError> { + if buf.is_empty() || (allow_skip && out_ptr == SENTINEL) { + return Ok(()); + } + + let buf_len = buf.len() as u32; + if let Some(costs) = create_token(buf_len) { + self.charge_gas(costs)?; + } + + memory.write(out_ptr, buf) + } + + /// Computes the given hash function on the supplied input. + /// + /// Reads from the sandboxed input buffer into an intermediate buffer. + /// Returns the result directly to the output buffer of the sandboxed memory. + /// + /// It is the callers responsibility to provide an output buffer that + /// is large enough to hold the expected amount of bytes returned by the + /// chosen hash function. + /// + /// # Note + /// + /// The `input` and `output` buffers may overlap. + fn compute_hash_on_intermediate_buffer( + &self, + memory: &mut M, + hash_fn: F, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), DispatchError> + where + F: FnOnce(&[u8]) -> R, + R: AsRef<[u8]>, + { + // Copy input into supervisor memory. + let input = memory.read(input_ptr, input_len)?; + // Compute the hash on the input buffer using the given hash function. + let hash = hash_fn(&input); + // Write the resulting hash back into the sandboxed output buffer. + memory.write(output_ptr, hash.as_ref())?; + Ok(()) + } + + /// Fallible conversion of a `ExecError` to `ReturnErrorCode`. + /// + /// This is used when converting the error returned from a subcall in order to decide + /// whether to trap the caller or allow handling of the error. + fn exec_error_into_return_code(from: ExecError) -> Result { + use crate::exec::ErrorOrigin::Callee; + use ReturnErrorCode::*; + + let transfer_failed = Error::::TransferFailed.into(); + let out_of_gas = Error::::OutOfGas.into(); + let out_of_deposit = Error::::StorageDepositLimitExhausted.into(); + let duplicate_contract = Error::::DuplicateContract.into(); + let unsupported_precompile = Error::::UnsupportedPrecompileAddress.into(); + + // errors in the callee do not trap the caller + match (from.error, from.origin) { + (err, _) if err == transfer_failed => Ok(TransferFailed), + (err, _) if err == duplicate_contract => Ok(DuplicateContractAddress), + (err, _) if err == unsupported_precompile => Err(err), + (err, Callee) if err == out_of_gas || err == out_of_deposit => Ok(OutOfResources), + (_, Callee) => Ok(CalleeTrapped), + (err, _) => Err(err), + } + } + + fn decode_key(&self, memory: &M, key_ptr: u32, key_len: u32) -> Result { + let res = match key_len { + SENTINEL => { + let mut buffer = [0u8; 32]; + memory.read_into_buf(key_ptr, buffer.as_mut())?; + Ok(Key::from_fixed(buffer)) + }, + len => { + ensure!(len <= limits::STORAGE_KEY_BYTES, Error::::DecodingFailed); + let key = memory.read(key_ptr, len)?; + Key::try_from_var(key) + }, + }; + + res.map_err(|_| Error::::DecodingFailed.into()) + } + + fn is_transient(flags: u32) -> Result { + StorageFlags::from_bits(flags) + .ok_or_else(|| >::InvalidStorageFlags.into()) + .map(|flags| flags.contains(StorageFlags::TRANSIENT)) + } + + fn set_storage( + &mut self, + memory: &M, + flags: u32, + key_ptr: u32, + key_len: u32, + value: StorageValue, + ) -> Result { + let transient = Self::is_transient(flags)?; + let costs = |new_bytes: u32, old_bytes: u32| { + if transient { + RuntimeCosts::SetTransientStorage { new_bytes, old_bytes } + } else { + RuntimeCosts::SetStorage { new_bytes, old_bytes } + } + }; + + let value_len = match &value { + StorageValue::Memory { ptr: _, len } => *len, + StorageValue::Value(data) => data.len() as u32, + }; + + let max_size = self.ext.max_value_size(); + let charged = self.charge_gas(costs(value_len, self.ext.max_value_size()))?; + if value_len > max_size { + return Err(Error::::ValueTooLarge.into()); + } + + let key = self.decode_key(memory, key_ptr, key_len)?; + + let value = match value { + StorageValue::Memory { ptr, len } => Some(memory.read(ptr, len)?), + StorageValue::Value(data) => Some(data), + }; + + let write_outcome = if transient { + self.ext.set_transient_storage(&key, value, false)? + } else { + self.ext.set_storage(&key, value, false)? + }; + + self.adjust_gas(charged, costs(value_len, write_outcome.old_len())); + Ok(write_outcome.old_len_with_sentinel()) + } + + fn clear_storage( + &mut self, + memory: &M, + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + let transient = Self::is_transient(flags)?; + let costs = |len| { + if transient { + RuntimeCosts::ClearTransientStorage(len) + } else { + RuntimeCosts::ClearStorage(len) + } + }; + let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let key = self.decode_key(memory, key_ptr, key_len)?; + let outcome = if transient { + self.ext.set_transient_storage(&key, None, false)? + } else { + self.ext.set_storage(&key, None, false)? + }; + self.adjust_gas(charged, costs(outcome.old_len())); + Ok(outcome.old_len_with_sentinel()) + } + + fn get_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + read_mode: StorageReadMode, + ) -> Result { + let transient = Self::is_transient(flags)?; + let costs = |len| { + if transient { + RuntimeCosts::GetTransientStorage(len) + } else { + RuntimeCosts::GetStorage(len) + } + }; + let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let key = self.decode_key(memory, key_ptr, key_len)?; + let outcome = if transient { + self.ext.get_transient_storage(&key) + } else { + self.ext.get_storage(&key) + }; + + if let Some(value) = outcome { + self.adjust_gas(charged, costs(value.len() as u32)); + + match read_mode { + StorageReadMode::FixedOutput32 => { + let mut fixed_output = [0u8; 32]; + let len = value.len().min(fixed_output.len()); + fixed_output[..len].copy_from_slice(&value[..len]); + + self.write_fixed_sandbox_output( + memory, + out_ptr, + &fixed_output, + false, + already_charged, + )?; + Ok(ReturnErrorCode::Success) + }, + StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr } => { + self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &value, + false, + already_charged, + )?; + Ok(ReturnErrorCode::Success) + }, + } + } else { + self.adjust_gas(charged, costs(0)); + + match read_mode { + StorageReadMode::FixedOutput32 => { + self.write_fixed_sandbox_output( + memory, + out_ptr, + &[0u8; 32], + false, + already_charged, + )?; + Ok(ReturnErrorCode::Success) + }, + StorageReadMode::VariableOutput { .. } => Ok(ReturnErrorCode::KeyNotFound), + } + } + } + + fn contains_storage( + &mut self, + memory: &M, + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + let transient = Self::is_transient(flags)?; + let costs = |len| { + if transient { + RuntimeCosts::ContainsTransientStorage(len) + } else { + RuntimeCosts::ContainsStorage(len) + } + }; + let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let key = self.decode_key(memory, key_ptr, key_len)?; + let outcome = if transient { + self.ext.get_transient_storage_size(&key) + } else { + self.ext.get_storage_size(&key) + }; + self.adjust_gas(charged, costs(outcome.unwrap_or(0))); + Ok(outcome.unwrap_or(SENTINEL)) + } + + fn take_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { + let transient = Self::is_transient(flags)?; + let costs = |len| { + if transient { + RuntimeCosts::TakeTransientStorage(len) + } else { + RuntimeCosts::TakeStorage(len) + } + }; + let charged = self.charge_gas(costs(self.ext.max_value_size()))?; + let key = self.decode_key(memory, key_ptr, key_len)?; + let outcome = if transient { + self.ext.set_transient_storage(&key, None, true)? + } else { + self.ext.set_storage(&key, None, true)? + }; + + if let crate::storage::WriteOutcome::Taken(value) = outcome { + self.adjust_gas(charged, costs(value.len() as u32)); + self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &value, + false, + already_charged, + )?; + Ok(ReturnErrorCode::Success) + } else { + self.adjust_gas(charged, costs(0)); + Ok(ReturnErrorCode::KeyNotFound) + } + } + + fn call( + &mut self, + memory: &mut M, + flags: CallFlags, + call_type: CallType, + callee_ptr: u32, + deposit_ptr: u32, + weight: Weight, + input_data_ptr: u32, + input_data_len: u32, + output_ptr: u32, + output_len_ptr: u32, + ) -> Result { + let callee = memory.read_h160(callee_ptr)?; + let precompile = >::get::(&callee.as_fixed_bytes()); + match &precompile { + Some(precompile) if precompile.has_contract_info() => + self.charge_gas(RuntimeCosts::PrecompileWithInfoBase)?, + Some(_) => self.charge_gas(RuntimeCosts::PrecompileBase)?, + None => self.charge_gas(call_type.cost())?, + }; + + let deposit_limit = memory.read_u256(deposit_ptr)?; + + // we do check this in exec.rs but we want to error out early + if input_data_len > limits::CALLDATA_BYTES { + Err(>::CallDataTooLarge)?; + } + + let input_data = if flags.contains(CallFlags::CLONE_INPUT) { + let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; + charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; + input.clone() + } else if flags.contains(CallFlags::FORWARD_INPUT) { + self.input_data.take().ok_or(Error::::InputForwarded)? + } else { + if precompile.is_some() { + self.charge_gas(RuntimeCosts::PrecompileDecode(input_data_len))?; + } else { + self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; + } + memory.read(input_data_ptr, input_data_len)? + }; + + memory.reset_interpreter_cache(); + + let call_outcome = match call_type { + CallType::Call { value_ptr } => { + let read_only = flags.contains(CallFlags::READ_ONLY); + let value = memory.read_u256(value_ptr)?; + if value > 0u32.into() { + // If the call value is non-zero and state change is not allowed, issue an + // error. + if read_only || self.ext.is_read_only() { + return Err(Error::::StateChangeDenied.into()); + } + + self.charge_gas(RuntimeCosts::CallTransferSurcharge { + dust_transfer: Pallet::::has_dust(value), + })?; + } + self.ext.call( + weight, + deposit_limit, + &callee, + value, + input_data, + flags.contains(CallFlags::ALLOW_REENTRY), + read_only, + ) + }, + CallType::DelegateCall => { + if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) { + return Err(Error::::InvalidCallFlags.into()); + } + self.ext.delegate_call(weight, deposit_limit, callee, input_data) + }, + }; + + match call_outcome { + // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to + // a halt anyways without anymore code being executed. + Ok(_) if flags.contains(CallFlags::TAIL_CALL) => { + let output = mem::take(self.ext.last_frame_output_mut()); + return Err(TrapReason::Return(ReturnData { + flags: output.flags.bits(), + data: output.data, + })); + }, + Ok(_) => { + let output = mem::take(self.ext.last_frame_output_mut()); + let write_result = self.write_sandbox_output( + memory, + output_ptr, + output_len_ptr, + &output.data, + true, + |len| Some(RuntimeCosts::CopyToContract(len)), + ); + *self.ext.last_frame_output_mut() = output; + write_result?; + Ok(self.ext.last_frame_output().into()) + }, + Err(err) => { + let error_code = Self::exec_error_into_return_code(err)?; + memory.write(output_len_ptr, &0u32.to_le_bytes())?; + Ok(error_code) + }, + } + } + + fn instantiate( + &mut self, + memory: &mut M, + code_hash_ptr: u32, + weight: Weight, + deposit_ptr: u32, + value_ptr: u32, + input_data_ptr: u32, + input_data_len: u32, + address_ptr: u32, + output_ptr: u32, + output_len_ptr: u32, + salt_ptr: u32, + ) -> Result { + let value = match memory.read_u256(value_ptr) { + Ok(value) => { + self.charge_gas(RuntimeCosts::Instantiate { + input_data_len, + balance_transfer: Pallet::::has_balance(value), + dust_transfer: Pallet::::has_dust(value), + })?; + value + }, + Err(err) => { + self.charge_gas(RuntimeCosts::Instantiate { + input_data_len: 0, + balance_transfer: false, + dust_transfer: false, + })?; + return Err(err.into()); + }, + }; + let deposit_limit: U256 = memory.read_u256(deposit_ptr)?; + let code_hash = memory.read_h256(code_hash_ptr)?; + if input_data_len > limits::CALLDATA_BYTES { + Err(>::CallDataTooLarge)?; + } + let input_data = memory.read(input_data_ptr, input_data_len)?; + let salt = if salt_ptr == SENTINEL { + None + } else { + let salt: [u8; 32] = memory.read_array(salt_ptr)?; + Some(salt) + }; + + memory.reset_interpreter_cache(); + + match self.ext.instantiate( + weight, + deposit_limit, + code_hash, + value, + input_data, + salt.as_ref(), + ) { + Ok(address) => { + if !self.ext.last_frame_output().flags.contains(ReturnFlags::REVERT) { + self.write_fixed_sandbox_output( + memory, + address_ptr, + &address.as_bytes(), + true, + already_charged, + )?; + } + let output = mem::take(self.ext.last_frame_output_mut()); + let write_result = self.write_sandbox_output( + memory, + output_ptr, + output_len_ptr, + &output.data, + true, + |len| Some(RuntimeCosts::CopyToContract(len)), + ); + *self.ext.last_frame_output_mut() = output; + write_result?; + Ok(self.ext.last_frame_output().into()) + }, + Err(err) => Ok(Self::exec_error_into_return_code(err)?), + } + } +} + +pub struct PreparedCall<'a, E: Ext> { + module: polkavm::Module, + instance: polkavm::RawInstance, + runtime: Runtime<'a, E, polkavm::RawInstance>, +} + +impl<'a, E: Ext> PreparedCall<'a, E> +where + BalanceOf: Into, + BalanceOf: TryFrom, +{ + pub fn call(mut self) -> ExecResult { + let exec_result = loop { + let interrupt = self.instance.run(); + if let Some(exec_result) = + self.runtime.handle_interrupt(interrupt, &self.module, &mut self.instance) + { + break exec_result + } + }; + let _ = self.runtime.ext().gas_meter_mut().sync_from_executor(self.instance.gas())?; + exec_result + } + + /// The guest memory address at which the aux data is located. + #[cfg(feature = "runtime-benchmarks")] + pub fn aux_data_base(&self) -> u32 { + self.instance.module().memory_map().aux_data_address() + } + + /// Copies `data` to the aux data at address `offset`. + /// + /// It sets `a0` to the beginning of data inside the aux data. + /// It sets `a1` to the value passed. + /// + /// Only used in benchmarking so far. + #[cfg(feature = "runtime-benchmarks")] + pub fn setup_aux_data( + &mut self, + data: &[u8], + offset: u32, + a1: u64, + ) -> frame_support::dispatch::DispatchResult { + let a0 = self.aux_data_base().saturating_add(offset); + self.instance.write_memory(a0, data).map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to write aux data: {err:?}"); + Error::::CodeRejected + })?; + self.instance.set_reg(polkavm::Reg::A0, a0.into()); + self.instance.set_reg(polkavm::Reg::A1, a1); + Ok(()) + } +} diff --git a/substrate/frame/revive/src/vm/pvm/env.rs b/substrate/frame/revive/src/vm/pvm/env.rs new file mode 100644 index 0000000000000..0255670a4f529 --- /dev/null +++ b/substrate/frame/revive/src/vm/pvm/env.rs @@ -0,0 +1,1037 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; + +use crate::{ + address::AddressMapper, + exec::Ext, + limits, + primitives::ExecReturnValue, + storage::meter::Diff, + vm::{ExportedFunction, RuntimeCosts}, + AccountIdOf, BalanceOf, CodeInfo, Config, ContractBlob, Error, Weight, SENTINEL, +}; +use alloc::vec::Vec; +use codec::{Encode, MaxEncodedLen}; +use core::mem; +use frame_support::traits::Get; +use pallet_revive_proc_macro::define_env; +use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags}; +use sp_core::{H160, H256, U256}; +use sp_io::hashing::keccak_256; +use sp_runtime::DispatchError; + +impl ContractBlob { + /// Compile and instantiate contract. + /// + /// `aux_data_size` is only used for runtime benchmarks. Real contracts + /// don't make use of this buffer. Hence this should not be set to anything + /// other than `0` when not used for benchmarking. + pub fn prepare_call>( + self, + mut runtime: Runtime, + entry_point: ExportedFunction, + aux_data_size: u32, + ) -> Result, ExecError> { + let mut config = polkavm::Config::default(); + config.set_backend(Some(polkavm::BackendKind::Interpreter)); + config.set_cache_enabled(false); + #[cfg(feature = "std")] + if std::env::var_os("REVIVE_USE_COMPILER").is_some() { + log::warn!(target: LOG_TARGET, "Using PolkaVM compiler backend because env var REVIVE_USE_COMPILER is set"); + config.set_backend(Some(polkavm::BackendKind::Compiler)); + } + let engine = polkavm::Engine::new(&config).expect( + "on-chain (no_std) use of interpreter is hard coded. + interpreter is available on all platforms; qed", + ); + + let mut module_config = polkavm::ModuleConfig::new(); + module_config.set_page_size(limits::PAGE_SIZE); + module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync)); + module_config.set_allow_sbrk(false); + module_config.set_aux_data_size(aux_data_size); + let module = polkavm::Module::new(&engine, &module_config, self.code.into_inner().into()) + .map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}"); + Error::::CodeRejected + })?; + + let entry_program_counter = module + .exports() + .find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes()) + .ok_or_else(|| >::CodeRejected)? + .program_counter(); + + let gas_limit_polkavm: polkavm::Gas = runtime.ext().gas_meter_mut().engine_fuel_left()?; + + let mut instance = module.instantiate().map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to instantiate polkavm module: {err:?}"); + Error::::CodeRejected + })?; + + instance.set_gas(gas_limit_polkavm); + instance + .set_interpreter_cache_size_limit(Some(polkavm::SetCacheSizeLimitArgs { + max_block_size: limits::code::BASIC_BLOCK_SIZE, + max_cache_size_bytes: limits::code::INTERPRETER_CACHE_BYTES + .try_into() + .map_err(|_| Error::::CodeRejected)?, + })) + .map_err(|_| Error::::CodeRejected)?; + instance.prepare_call_untyped(entry_program_counter, &[]); + + Ok(PreparedCall { module, instance, runtime }) + } +} + +impl ContractBlob +where + BalanceOf: Into + TryFrom, +{ + /// We only check for size and nothing else when the code is uploaded. + pub fn from_pvm_code(code: Vec, owner: AccountIdOf) -> Result { + // We do validation only when new code is deployed. This allows us to increase + // the limits later without affecting already deployed code. + let available_syscalls = list_syscalls(T::UnsafeUnstableInterface::get()); + let code = limits::code::enforce::(code, available_syscalls)?; + + let code_len = code.len() as u32; + let bytes_added = code_len.saturating_add(>::max_encoded_len() as u32); + let deposit = Diff { bytes_added, items_added: 2, ..Default::default() } + .update_contract::(None) + .charge_or_zero(); + let code_info = CodeInfo { + owner, + deposit, + refcount: 0, + code_len, + behaviour_version: Default::default(), + }; + let code_hash = H256(sp_io::hashing::keccak_256(&code)); + Ok(ContractBlob { code, code_info, code_hash }) + } +} + +impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { + pub fn handle_interrupt( + &mut self, + interrupt: Result, + module: &polkavm::Module, + instance: &mut M, + ) -> Option { + use polkavm::InterruptKind::*; + + match interrupt { + Err(error) => { + // in contrast to the other returns this "should" not happen: log level error + log::error!(target: LOG_TARGET, "polkavm execution error: {error}"); + Some(Err(Error::::ExecutionFailed.into())) + }, + Ok(Finished) => + Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })), + Ok(Trap) => Some(Err(Error::::ContractTrapped.into())), + Ok(Segfault(_)) => Some(Err(Error::::ExecutionFailed.into())), + Ok(NotEnoughGas) => Some(Err(Error::::OutOfGas.into())), + Ok(Step) => None, + Ok(Ecalli(idx)) => { + // This is a special hard coded syscall index which is used by benchmarks + // to abort contract execution. It is used to terminate the execution without + // breaking up a basic block. The fixed index is used so that the benchmarks + // don't have to deal with import tables. + if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL { + return Some(Ok(ExecReturnValue { + flags: ReturnFlags::empty(), + data: Vec::new(), + })) + } + let Some(syscall_symbol) = module.imports().get(idx) else { + return Some(Err(>::InvalidSyscall.into())); + }; + match self.handle_ecall(instance, syscall_symbol.as_bytes()) { + Ok(None) => None, + Ok(Some(return_value)) => { + instance.write_output(return_value); + None + }, + Err(TrapReason::Return(ReturnData { flags, data })) => + match ReturnFlags::from_bits(flags) { + None => Some(Err(Error::::InvalidCallFlags.into())), + Some(flags) => Some(Ok(ExecReturnValue { flags, data })), + }, + Err(TrapReason::Termination) => Some(Ok(Default::default())), + Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())), + } + }, + } + } +} + +// This is the API exposed to contracts. +// +// # Note +// +// Any input that leads to a out of bound error (reading or writing) or failing to decode +// data passed to the supervisor will lead to a trap. This is not documented explicitly +// for every function. +#[define_env] +pub mod env { + /// Noop function used to benchmark the time it takes to execute an empty function. + /// + /// Marked as stable because it needs to be called from benchmarks even when the benchmarked + /// parachain has unstable functions disabled. + #[cfg(feature = "runtime-benchmarks")] + #[stable] + fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> { + Ok(()) + } + + /// Set the value at the given key in the contract storage. + /// See [`pallet_revive_uapi::HostFn::set_storage_v2`] + #[stable] + #[mutating] + fn set_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + value_ptr: u32, + value_len: u32, + ) -> Result { + self.set_storage( + memory, + flags, + key_ptr, + key_len, + StorageValue::Memory { ptr: value_ptr, len: value_len }, + ) + } + + /// Sets the storage at a fixed 256-bit key with a fixed 256-bit value. + /// See [`pallet_revive_uapi::HostFn::set_storage_or_clear`]. + #[stable] + #[mutating] + fn set_storage_or_clear( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + value_ptr: u32, + ) -> Result { + let value = memory.read(value_ptr, 32)?; + + if value.iter().all(|&b| b == 0) { + self.clear_storage(memory, flags, key_ptr, SENTINEL) + } else { + self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value)) + } + } + + /// Retrieve the value under the given key from storage. + /// See [`pallet_revive_uapi::HostFn::get_storage`] + #[stable] + fn get_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { + self.get_storage( + memory, + flags, + key_ptr, + key_len, + out_ptr, + StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr }, + ) + } + + /// Reads the storage at a fixed 256-bit key and writes back a fixed 256-bit value. + /// See [`pallet_revive_uapi::HostFn::get_storage_or_zero`]. + #[stable] + fn get_storage_or_zero( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + out_ptr: u32, + ) -> Result<(), TrapReason> { + let _ = self.get_storage( + memory, + flags, + key_ptr, + SENTINEL, + out_ptr, + StorageReadMode::FixedOutput32, + )?; + + Ok(()) + } + + /// Make a call to another contract. + /// See [`pallet_revive_uapi::HostFn::call`]. + #[stable] + fn call( + &mut self, + memory: &mut M, + flags_and_callee: u64, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_and_value: u64, + input_data: u64, + output_data: u64, + ) -> Result { + let (flags, callee_ptr) = extract_hi_lo(flags_and_callee); + let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); + let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); + let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); + + self.call( + memory, + CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, + CallType::Call { value_ptr }, + callee_ptr, + deposit_ptr, + Weight::from_parts(ref_time_limit, proof_size_limit), + input_data_ptr, + input_data_len, + output_ptr, + output_len_ptr, + ) + } + + /// Execute code in the context (storage, caller, value) of the current contract. + /// See [`pallet_revive_uapi::HostFn::delegate_call`]. + #[stable] + fn delegate_call( + &mut self, + memory: &mut M, + flags_and_callee: u64, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_ptr: u32, + input_data: u64, + output_data: u64, + ) -> Result { + let (flags, address_ptr) = extract_hi_lo(flags_and_callee); + let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); + let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); + + self.call( + memory, + CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, + CallType::DelegateCall, + address_ptr, + deposit_ptr, + Weight::from_parts(ref_time_limit, proof_size_limit), + input_data_ptr, + input_data_len, + output_ptr, + output_len_ptr, + ) + } + + /// Instantiate a contract with the specified code hash. + /// See [`pallet_revive_uapi::HostFn::instantiate`]. + #[stable] + #[mutating] + fn instantiate( + &mut self, + memory: &mut M, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_and_value: u64, + input_data: u64, + output_data: u64, + address_and_salt: u64, + ) -> Result { + let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); + let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data); + let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); + let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt); + let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else { + return Err(Error::::OutOfBounds.into()); + }; + let Some(input_data_len) = input_data_len.checked_sub(32) else { + return Err(Error::::OutOfBounds.into()); + }; + + self.instantiate( + memory, + code_hash_ptr, + Weight::from_parts(ref_time_limit, proof_size_limit), + deposit_ptr, + value_ptr, + input_data_ptr, + input_data_len, + address_ptr, + output_ptr, + output_len_ptr, + salt_ptr, + ) + } + + /// Returns the total size of the contract call input data. + /// See [`pallet_revive_uapi::HostFn::call_data_size `]. + #[stable] + fn call_data_size(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallDataSize)?; + Ok(self + .input_data + .as_ref() + .map(|input| input.len().try_into().expect("usize fits into u64; qed")) + .unwrap_or_default()) + } + + /// Stores the input passed by the caller into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::call_data_copy`]. + #[stable] + fn call_data_copy( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len: u32, + offset: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?; + + let Some(input) = self.input_data.as_ref() else { + return Err(Error::::InputForwarded.into()); + }; + + let start = offset as usize; + if start >= input.len() { + memory.zero(out_ptr, out_len)?; + return Ok(()); + } + + let end = start.saturating_add(out_len as usize).min(input.len()); + memory.write(out_ptr, &input[start..end])?; + + let bytes_written = (end - start) as u32; + memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?; + + Ok(()) + } + + /// Stores the U256 value at given call input `offset` into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::call_data_load`]. + #[stable] + fn call_data_load( + &mut self, + memory: &mut M, + out_ptr: u32, + offset: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CallDataLoad)?; + + let Some(input) = self.input_data.as_ref() else { + return Err(Error::::InputForwarded.into()); + }; + + let mut data = [0; 32]; + let start = offset as usize; + let data = if start >= input.len() { + data // Any index is valid to request; OOB offsets return zero. + } else { + let end = start.saturating_add(32).min(input.len()); + data[..end - start].copy_from_slice(&input[start..end]); + data.reverse(); + data // Solidity expects right-padded data + }; + + self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?; + + Ok(()) + } + + /// Cease contract execution and save a data buffer as a result of the execution. + /// See [`pallet_revive_uapi::HostFn::return_value`]. + #[stable] + fn seal_return( + &mut self, + memory: &mut M, + flags: u32, + data_ptr: u32, + data_len: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?; + if data_len > limits::CALLDATA_BYTES { + Err(>::ReturnDataTooLarge)?; + } + Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? })) + } + + /// Stores the address of the caller into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::caller`]. + #[stable] + fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Caller)?; + let caller = ::AddressMapper::to_address(self.ext.caller().account_id()?); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + caller.as_bytes(), + false, + already_charged, + )?) + } + + /// Stores the address of the call stack origin into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::origin`]. + #[stable] + fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Origin)?; + let origin = ::AddressMapper::to_address(self.ext.origin().account_id()?); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + origin.as_bytes(), + false, + already_charged, + )?) + } + + /// Retrieve the code hash for a specified contract address. + /// See [`pallet_revive_uapi::HostFn::code_hash`]. + #[stable] + fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CodeHash)?; + let address = memory.read_h160(addr_ptr)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.code_hash(&address).as_bytes(), + false, + already_charged, + )?) + } + + /// Retrieve the code size for a given contract address. + /// See [`pallet_revive_uapi::HostFn::code_size`]. + #[stable] + fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result { + self.charge_gas(RuntimeCosts::CodeSize)?; + let address = memory.read_h160(addr_ptr)?; + Ok(self.ext.code_size(&address)) + } + + /// Stores the address of the current contract into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::address`]. + #[stable] + fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Address)?; + let address = self.ext.address(); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + address.as_bytes(), + false, + already_charged, + )?) + } + + /// Stores the price for the specified amount of weight into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::weight_to_fee`]. + #[stable] + fn weight_to_fee( + &mut self, + memory: &mut M, + ref_time_limit: u64, + proof_size_limit: u64, + out_ptr: u32, + ) -> Result<(), TrapReason> { + let weight = Weight::from_parts(ref_time_limit, proof_size_limit); + self.charge_gas(RuntimeCosts::WeightToFee)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.get_weight_price(weight).encode(), + false, + already_charged, + )?) + } + + /// Stores the immutable data into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. + #[stable] + fn get_immutable_data( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { + // quering the length is free as it is stored with the contract metadata + let len = self.ext.immutable_data_len(); + self.charge_gas(RuntimeCosts::GetImmutableData(len))?; + let data = self.ext.get_immutable_data()?; + self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?; + Ok(()) + } + + /// Attaches the supplied immutable data to the currently executing contract. + /// See [`pallet_revive_uapi::HostFn::set_immutable_data`]. + #[stable] + fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { + if len > limits::IMMUTABLE_BYTES { + return Err(Error::::OutOfBounds.into()); + } + self.charge_gas(RuntimeCosts::SetImmutableData(len))?; + let buf = memory.read(ptr, len)?; + let data = buf.try_into().expect("bailed out earlier; qed"); + self.ext.set_immutable_data(data)?; + Ok(()) + } + + /// Stores the *free* balance of the current account into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::balance`]. + #[stable] + fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Balance)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.balance().to_little_endian(), + false, + already_charged, + )?) + } + + /// Stores the *free* balance of the supplied address into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::balance`]. + #[stable] + fn balance_of( + &mut self, + memory: &mut M, + addr_ptr: u32, + out_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BalanceOf)?; + let address = memory.read_h160(addr_ptr)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.balance_of(&address).to_little_endian(), + false, + already_charged, + )?) + } + + /// Returns the chain ID. + /// See [`pallet_revive_uapi::HostFn::chain_id`]. + #[stable] + fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &U256::from(::ChainId::get()).to_little_endian(), + false, + |_| Some(RuntimeCosts::CopyToContract(32)), + )?) + } + + /// Returns the block ref_time limit. + /// See [`pallet_revive_uapi::HostFn::gas_limit`]. + #[stable] + fn gas_limit(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::GasLimit)?; + Ok(::BlockWeights::get().max_block.ref_time()) + } + + /// Stores the value transferred along with this call/instantiate into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::value_transferred`]. + #[stable] + fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::ValueTransferred)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.value_transferred().to_little_endian(), + false, + already_charged, + )?) + } + + /// Returns the simulated ethereum `GASPRICE` value. + /// See [`pallet_revive_uapi::HostFn::gas_price`]. + #[stable] + fn gas_price(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::GasPrice)?; + Ok(GAS_PRICE.into()) + } + + /// Returns the simulated ethereum `BASEFEE` value. + /// See [`pallet_revive_uapi::HostFn::base_fee`]. + #[stable] + fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BaseFee)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &U256::zero().to_little_endian(), + false, + already_charged, + )?) + } + + /// Load the latest block timestamp into the supplied buffer + /// See [`pallet_revive_uapi::HostFn::now`]. + #[stable] + fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Now)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.now().to_little_endian(), + false, + already_charged, + )?) + } + + /// Deposit a contract event with the data buffer and optional list of topics. + /// See [pallet_revive_uapi::HostFn::deposit_event] + #[stable] + #[mutating] + fn deposit_event( + &mut self, + memory: &mut M, + topics_ptr: u32, + num_topic: u32, + data_ptr: u32, + data_len: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?; + + if num_topic > limits::NUM_EVENT_TOPICS { + return Err(Error::::TooManyTopics.into()); + } + + if data_len > self.ext.max_value_size() { + return Err(Error::::ValueTooLarge.into()); + } + + let topics: Vec = match num_topic { + 0 => Vec::new(), + _ => { + let mut v = Vec::with_capacity(num_topic as usize); + let topics_len = num_topic * H256::len_bytes() as u32; + let buf = memory.read(topics_ptr, topics_len)?; + for chunk in buf.chunks_exact(H256::len_bytes()) { + v.push(H256::from_slice(chunk)); + } + v + }, + }; + + let event_data = memory.read(data_ptr, data_len)?; + self.ext.deposit_event(topics, event_data); + Ok(()) + } + + /// Stores the current block number of the current contract into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::block_number`]. + #[stable] + fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BlockNumber)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.block_number().to_little_endian(), + false, + already_charged, + )?) + } + + /// Stores the block hash at given block height into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::block_hash`]. + #[stable] + fn block_hash( + &mut self, + memory: &mut M, + block_number_ptr: u32, + out_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BlockHash)?; + let block_number = memory.read_u256(block_number_ptr)?; + let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero()); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &block_hash.as_bytes(), + false, + already_charged, + )?) + } + + /// Stores the current block author into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::block_author`]. + #[stable] + fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BlockAuthor)?; + let block_author = self.ext.block_author().unwrap_or(H160::zero()); + + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &block_author.as_bytes(), + false, + already_charged, + )?) + } + + /// Computes the KECCAK 256-bit hash on the given input buffer. + /// See [`pallet_revive_uapi::HostFn::hash_keccak_256`]. + #[stable] + fn hash_keccak_256( + &mut self, + memory: &mut M, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; + Ok(self.compute_hash_on_intermediate_buffer( + memory, keccak_256, input_ptr, input_len, output_ptr, + )?) + } + + /// Stores the length of the data returned by the last call into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data_size`]. + #[stable] + fn return_data_size(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::ReturnDataSize)?; + Ok(self + .ext + .last_frame_output() + .data + .len() + .try_into() + .expect("usize fits into u64; qed")) + } + + /// Stores data returned by the last call, starting from `offset`, into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data`]. + #[stable] + fn return_data_copy( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + offset: u32, + ) -> Result<(), TrapReason> { + let output = mem::take(self.ext.last_frame_output_mut()); + let result = if offset as usize > output.data.len() { + Err(Error::::OutOfBounds.into()) + } else { + self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &output.data[offset as usize..], + false, + |len| Some(RuntimeCosts::CopyToContract(len)), + ) + }; + *self.ext.last_frame_output_mut() = output; + Ok(result?) + } + + /// Returns the amount of ref_time left. + /// See [`pallet_revive_uapi::HostFn::ref_time_left`]. + #[stable] + fn ref_time_left(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::RefTimeLeft)?; + Ok(self.ext.gas_meter().gas_left().ref_time()) + } + + /// Checks whether the caller of the current contract is the origin of the whole call stack. + /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. + fn caller_is_origin(&mut self, _memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallerIsOrigin)?; + Ok(self.ext.caller_is_origin() as u32) + } + + /// Checks whether the caller of the current contract is root. + /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. + fn caller_is_root(&mut self, _memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallerIsRoot)?; + Ok(self.ext.caller_is_root() as u32) + } + + /// Clear the value at the given key in the contract storage. + /// See [`pallet_revive_uapi::HostFn::clear_storage`] + #[mutating] + fn clear_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + self.clear_storage(memory, flags, key_ptr, key_len) + } + + /// Checks whether there is a value stored under the given key. + /// See [`pallet_revive_uapi::HostFn::contains_storage`] + fn contains_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + self.contains_storage(memory, flags, key_ptr, key_len) + } + + /// Calculates Ethereum address from the ECDSA compressed public key and stores + /// See [`pallet_revive_uapi::HostFn::ecdsa_to_eth_address`]. + fn ecdsa_to_eth_address( + &mut self, + memory: &mut M, + key_ptr: u32, + out_ptr: u32, + ) -> Result { + self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; + let mut compressed_key: [u8; 33] = [0; 33]; + memory.read_into_buf(key_ptr, &mut compressed_key)?; + let result = self.ext.ecdsa_to_eth_address(&compressed_key); + match result { + Ok(eth_address) => { + memory.write(out_ptr, eth_address.as_ref())?; + Ok(ReturnErrorCode::Success) + }, + Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed), + } + } + + /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. + fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::MinimumBalance)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.minimum_balance().to_little_endian(), + false, + already_charged, + )?) + } + + /// Retrieve the code hash of the currently executing contract. + /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. + fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::OwnCodeHash)?; + let code_hash = *self.ext.own_code_hash(); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + code_hash.as_bytes(), + false, + already_charged, + )?) + } + + /// Replace the contract code at the specified address with new code. + /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. + /// + /// Disabled until the internal implementation takes care of collecting + /// the immutable data of the new code hash. + #[mutating] + fn set_code_hash(&mut self, memory: &mut M, code_hash_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::SetCodeHash)?; + let code_hash: H256 = memory.read_h256(code_hash_ptr)?; + self.ext.set_code_hash(code_hash)?; + Ok(()) + } + + /// Verify a sr25519 signature + /// See [`pallet_revive_uapi::HostFn::sr25519_verify`]. + fn sr25519_verify( + &mut self, + memory: &mut M, + signature_ptr: u32, + pub_key_ptr: u32, + message_len: u32, + message_ptr: u32, + ) -> Result { + self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; + + let mut signature: [u8; 64] = [0; 64]; + memory.read_into_buf(signature_ptr, &mut signature)?; + + let mut pub_key: [u8; 32] = [0; 32]; + memory.read_into_buf(pub_key_ptr, &mut pub_key)?; + + let message: Vec = memory.read(message_ptr, message_len)?; + + if self.ext.sr25519_verify(&signature, &message, &pub_key) { + Ok(ReturnErrorCode::Success) + } else { + Ok(ReturnErrorCode::Sr25519VerifyFailed) + } + } + + /// Retrieve and remove the value under the given key from storage. + /// See [`pallet_revive_uapi::HostFn::take_storage`] + #[mutating] + fn take_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { + self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) + } + + /// Remove the calling account and transfer remaining **free** balance. + /// See [`pallet_revive_uapi::HostFn::terminate`]. + #[mutating] + fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Terminate)?; + let beneficiary = memory.read_h160(beneficiary_ptr)?; + self.ext.terminate(&beneficiary)?; + Err(TrapReason::Termination) + } + + /// Stores the amount of weight left into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::weight_left`]. + fn weight_left( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::WeightLeft)?; + let gas_left = &self.ext.gas_meter().gas_left().encode(); + Ok(self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + gas_left, + false, + already_charged, + )?) + } +} diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs deleted file mode 100644 index 3a1cc07ab31a3..0000000000000 --- a/substrate/frame/revive/src/vm/runtime.rs +++ /dev/null @@ -1,2111 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Environment definition of the vm smart-contract runtime. - -use crate::{ - address::AddressMapper, - evm::runtime::GAS_PRICE, - exec::{ExecError, ExecResult, Ext, Key}, - gas::{ChargedAmount, Token}, - limits, - precompiles::{All as AllPrecompiles, Precompiles}, - primitives::ExecReturnValue, - weights::WeightInfo, - Config, Error, Pallet, LOG_TARGET, SENTINEL, -}; -use alloc::{vec, vec::Vec}; -use codec::Encode; -use core::{fmt, marker::PhantomData, mem}; -use frame_support::{ensure, traits::Get, weights::Weight}; -use pallet_revive_proc_macro::define_env; -use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags, StorageFlags}; -use sp_core::{H160, H256, U256}; -use sp_io::hashing::keccak_256; -use sp_runtime::{DispatchError, RuntimeDebug}; - -/// Abstraction over the memory access within syscalls. -/// -/// The reason for this abstraction is that we run syscalls on the host machine when -/// benchmarking them. In that case we have direct access to the contract's memory. However, when -/// running within PolkaVM we need to resort to copying as we can't map the contracts memory into -/// the host (as of now). -pub trait Memory { - /// Read designated chunk from the sandbox memory into the supplied buffer. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - requested buffer is not within the bounds of the sandbox memory. - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError>; - - /// Write the given buffer to the designated location in the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - designated area is not within the bounds of the sandbox memory. - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError>; - - /// Zero the designated location in the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - designated area is not within the bounds of the sandbox memory. - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError>; - - /// This will reset all compilation artifacts of the currently executing instance. - /// - /// This is used before we call into a new contract to free up some memory. Doing - /// so we make sure that we only ever have to hold one compilation cache at a time - /// independtently of of our call stack depth. - fn reset_interpreter_cache(&mut self); - - /// Read designated chunk from the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - requested buffer is not within the bounds of the sandbox memory. - fn read(&self, ptr: u32, len: u32) -> Result, DispatchError> { - let mut buf = vec![0u8; len as usize]; - self.read_into_buf(ptr, buf.as_mut_slice())?; - Ok(buf) - } - - /// Same as `read` but reads into a fixed size buffer. - fn read_array(&self, ptr: u32) -> Result<[u8; N], DispatchError> { - let mut buf = [0u8; N]; - self.read_into_buf(ptr, &mut buf)?; - Ok(buf) - } - - /// Read a `u32` from the sandbox memory. - fn read_u32(&self, ptr: u32) -> Result { - let buf: [u8; 4] = self.read_array(ptr)?; - Ok(u32::from_le_bytes(buf)) - } - - /// Read a `U256` from the sandbox memory. - fn read_u256(&self, ptr: u32) -> Result { - let buf: [u8; 32] = self.read_array(ptr)?; - Ok(U256::from_little_endian(&buf)) - } - - /// Read a `H160` from the sandbox memory. - fn read_h160(&self, ptr: u32) -> Result { - let mut buf = H160::default(); - self.read_into_buf(ptr, buf.as_bytes_mut())?; - Ok(buf) - } - - /// Read a `H256` from the sandbox memory. - fn read_h256(&self, ptr: u32) -> Result { - let mut code_hash = H256::default(); - self.read_into_buf(ptr, code_hash.as_bytes_mut())?; - Ok(code_hash) - } -} - -/// Allows syscalls access to the PolkaVM instance they are executing in. -/// -/// In case a contract is executing within PolkaVM its `memory` argument will also implement -/// this trait. The benchmarking implementation of syscalls will only require `Memory` -/// to be implemented. -pub trait PolkaVmInstance: Memory { - fn gas(&self) -> polkavm::Gas; - fn set_gas(&mut self, gas: polkavm::Gas); - fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64); - fn write_output(&mut self, output: u64); -} - -// Memory implementation used in benchmarking where guest memory is mapped into the host. -// -// Please note that we could optimize the `read_as_*` functions by decoding directly from -// memory without a copy. However, we don't do that because as it would change the behaviour -// of those functions: A `read_as` with a `len` larger than the actual type can succeed -// in the streaming implementation while it could fail with a segfault in the copy implementation. -#[cfg(feature = "runtime-benchmarks")] -impl Memory for [u8] { - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { - let ptr = ptr as usize; - let bound_checked = - self.get(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; - buf.copy_from_slice(bound_checked); - Ok(()) - } - - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { - let ptr = ptr as usize; - let bound_checked = - self.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; - bound_checked.copy_from_slice(buf); - Ok(()) - } - - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { - <[u8] as Memory>::write(self, ptr, &vec![0; len as usize]) - } - - fn reset_interpreter_cache(&mut self) {} -} - -impl Memory for polkavm::RawInstance { - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { - self.read_memory_into(ptr, buf) - .map(|_| ()) - .map_err(|_| Error::::OutOfBounds.into()) - } - - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { - self.write_memory(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) - } - - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { - self.zero_memory(ptr, len).map_err(|_| Error::::OutOfBounds.into()) - } - - fn reset_interpreter_cache(&mut self) { - self.reset_interpreter_cache(); - } -} - -impl PolkaVmInstance for polkavm::RawInstance { - fn gas(&self) -> polkavm::Gas { - self.gas() - } - - fn set_gas(&mut self, gas: polkavm::Gas) { - self.set_gas(gas) - } - - fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64) { - ( - self.reg(polkavm::Reg::A0), - self.reg(polkavm::Reg::A1), - self.reg(polkavm::Reg::A2), - self.reg(polkavm::Reg::A3), - self.reg(polkavm::Reg::A4), - self.reg(polkavm::Reg::A5), - ) - } - - fn write_output(&mut self, output: u64) { - self.set_reg(polkavm::Reg::A0, output); - } -} - -impl From<&ExecReturnValue> for ReturnErrorCode { - fn from(from: &ExecReturnValue) -> Self { - if from.flags.contains(ReturnFlags::REVERT) { - Self::CalleeReverted - } else { - Self::Success - } - } -} - -/// The data passed through when a contract uses `seal_return`. -#[derive(RuntimeDebug)] -pub struct ReturnData { - /// The flags as passed through by the contract. They are still unchecked and - /// will later be parsed into a `ReturnFlags` bitflags struct. - flags: u32, - /// The output buffer passed by the contract as return data. - data: Vec, -} - -/// Enumerates all possible reasons why a trap was generated. -/// -/// This is either used to supply the caller with more information about why an error -/// occurred (the SupervisorError variant). -/// The other case is where the trap does not constitute an error but rather was invoked -/// as a quick way to terminate the application (all other variants). -#[derive(RuntimeDebug)] -pub enum TrapReason { - /// The supervisor trapped the contract because of an error condition occurred during - /// execution in privileged code. - SupervisorError(DispatchError), - /// Signals that trap was generated in response to call `seal_return` host function. - Return(ReturnData), - /// Signals that a trap was generated in response to a successful call to the - /// `seal_terminate` host function. - Termination, -} - -impl> From for TrapReason { - fn from(from: T) -> Self { - Self::SupervisorError(from.into()) - } -} - -impl fmt::Display for TrapReason { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - Ok(()) - } -} - -#[cfg_attr(test, derive(Debug, PartialEq, Eq))] -#[derive(Copy, Clone)] -pub enum RuntimeCosts { - /// Base Weight of calling a host function. - HostFn, - /// Weight charged for copying data from the sandbox. - CopyFromContract(u32), - /// Weight charged for copying data to the sandbox. - CopyToContract(u32), - /// Weight of calling `seal_call_data_load``. - CallDataLoad, - /// Weight of calling `seal_call_data_copy`. - CallDataCopy(u32), - /// Weight of calling `seal_caller`. - Caller, - /// Weight of calling `seal_call_data_size`. - CallDataSize, - /// Weight of calling `seal_return_data_size`. - ReturnDataSize, - /// Weight of calling `seal_to_account_id`. - ToAccountId, - /// Weight of calling `seal_origin`. - Origin, - /// Weight of calling `seal_code_hash`. - CodeHash, - /// Weight of calling `seal_own_code_hash`. - OwnCodeHash, - /// Weight of calling `seal_code_size`. - CodeSize, - /// Weight of calling `seal_caller_is_origin`. - CallerIsOrigin, - /// Weight of calling `caller_is_root`. - CallerIsRoot, - /// Weight of calling `seal_address`. - Address, - /// Weight of calling `seal_ref_time_left`. - RefTimeLeft, - /// Weight of calling `seal_weight_left`. - WeightLeft, - /// Weight of calling `seal_balance`. - Balance, - /// Weight of calling `seal_balance_of`. - BalanceOf, - /// Weight of calling `seal_value_transferred`. - ValueTransferred, - /// Weight of calling `seal_minimum_balance`. - MinimumBalance, - /// Weight of calling `seal_block_number`. - BlockNumber, - /// Weight of calling `seal_block_hash`. - BlockHash, - /// Weight of calling `seal_block_author`. - BlockAuthor, - /// Weight of calling `seal_gas_price`. - GasPrice, - /// Weight of calling `seal_base_fee`. - BaseFee, - /// Weight of calling `seal_now`. - Now, - /// Weight of calling `seal_gas_limit`. - GasLimit, - /// Weight of calling `seal_weight_to_fee`. - WeightToFee, - /// Weight of calling `seal_terminate`. - Terminate, - /// Weight of calling `seal_deposit_event` with the given number of topics and event size. - DepositEvent { num_topic: u32, len: u32 }, - /// Weight of calling `seal_set_storage` for the given storage item sizes. - SetStorage { old_bytes: u32, new_bytes: u32 }, - /// Weight of calling `seal_clear_storage` per cleared byte. - ClearStorage(u32), - /// Weight of calling `seal_contains_storage` per byte of the checked item. - ContainsStorage(u32), - /// Weight of calling `seal_get_storage` with the specified size in storage. - GetStorage(u32), - /// Weight of calling `seal_take_storage` for the given size. - TakeStorage(u32), - /// Weight of calling `seal_set_transient_storage` for the given storage item sizes. - SetTransientStorage { old_bytes: u32, new_bytes: u32 }, - /// Weight of calling `seal_clear_transient_storage` per cleared byte. - ClearTransientStorage(u32), - /// Weight of calling `seal_contains_transient_storage` per byte of the checked item. - ContainsTransientStorage(u32), - /// Weight of calling `seal_get_transient_storage` with the specified size in storage. - GetTransientStorage(u32), - /// Weight of calling `seal_take_transient_storage` for the given size. - TakeTransientStorage(u32), - /// Base weight of calling `seal_call`. - CallBase, - /// Weight of calling `seal_delegate_call` for the given input size. - DelegateCallBase, - /// Weight of calling a precompile. - PrecompileBase, - /// Weight of calling a precompile that has a contract info. - PrecompileWithInfoBase, - /// Weight of reading and decoding the input to a precompile. - PrecompileDecode(u32), - /// Weight of the transfer performed during a call. - /// parameter `dust_transfer` indicates whether the transfer has a `dust` value. - CallTransferSurcharge { dust_transfer: bool }, - /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. - CallInputCloned(u32), - /// Weight of calling `seal_instantiate`. - Instantiate { input_data_len: u32, balance_transfer: bool, dust_transfer: bool }, - /// Weight of calling `Ripemd160` precompile for the given input size. - Ripemd160(u32), - /// Weight of calling `Sha256` precompile for the given input size. - HashSha256(u32), - /// Weight of calling `seal_hash_keccak_256` for the given input size. - HashKeccak256(u32), - /// Weight of calling the `System::hashBlake256` precompile function for the given input - /// size. - HashBlake256(u32), - /// Weight of calling `System::hashBlake128` precompile function for the given input size. - HashBlake128(u32), - /// Weight of calling `ECERecover` precompile. - EcdsaRecovery, - /// Weight of calling `seal_sr25519_verify` for the given input size. - Sr25519Verify(u32), - /// Weight charged by a precompile. - Precompile(Weight), - /// Weight of calling `seal_set_code_hash` - SetCodeHash, - /// Weight of calling `ecdsa_to_eth_address` - EcdsaToEthAddress, - /// Weight of calling `get_immutable_dependency` - GetImmutableData(u32), - /// Weight of calling `set_immutable_dependency` - SetImmutableData(u32), - /// Weight of calling `Bn128Add` precompile - Bn128Add, - /// Weight of calling `Bn128Add` precompile - Bn128Mul, - /// Weight of calling `Bn128Pairing` precompile for the given number of input pairs. - Bn128Pairing(u32), - /// Weight of calling `Identity` precompile for the given number of input length. - Identity(u32), - /// Weight of calling `Blake2F` precompile for the given number of rounds. - Blake2F(u32), - /// Weight of calling `Modexp` precompile - Modexp(u64), -} - -/// For functions that modify storage, benchmarks are performed with one item in the -/// storage. To account for the worst-case scenario, the weight of the overhead of -/// writing to or reading from full storage is included. For transient storage writes, -/// the rollback weight is added to reflect the worst-case scenario for this operation. -macro_rules! cost_storage { - (write_transient, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::rollback_transient_storage()) - .saturating_add(T::WeightInfo::set_transient_storage_full() - .saturating_sub(T::WeightInfo::set_transient_storage_empty())) - }; - - (read_transient, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::get_transient_storage_full() - .saturating_sub(T::WeightInfo::get_transient_storage_empty())) - }; - - (write, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::set_storage_full() - .saturating_sub(T::WeightInfo::set_storage_empty())) - }; - - (read, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::get_storage_full() - .saturating_sub(T::WeightInfo::get_storage_empty())) - }; -} - -macro_rules! cost_args { - // cost_args!(name, a, b, c) -> T::WeightInfo::name(a, b, c).saturating_sub(T::WeightInfo::name(0, 0, 0)) - ($name:ident, $( $arg: expr ),+) => { - (T::WeightInfo::$name($( $arg ),+).saturating_sub(cost_args!(@call_zero $name, $( $arg ),+))) - }; - // Transform T::WeightInfo::name(a, b, c) into T::WeightInfo::name(0, 0, 0) - (@call_zero $name:ident, $( $arg:expr ),*) => { - T::WeightInfo::$name($( cost_args!(@replace_token $arg) ),*) - }; - // Replace the token with 0. - (@replace_token $_in:tt) => { 0 }; -} - -impl Token for RuntimeCosts { - fn influence_lowest_gas_limit(&self) -> bool { - true - } - - fn weight(&self) -> Weight { - use self::RuntimeCosts::*; - match *self { - HostFn => cost_args!(noop_host_fn, 1), - CopyToContract(len) => T::WeightInfo::seal_copy_to_contract(len), - CopyFromContract(len) => T::WeightInfo::seal_return(len), - CallDataSize => T::WeightInfo::seal_call_data_size(), - ReturnDataSize => T::WeightInfo::seal_return_data_size(), - CallDataLoad => T::WeightInfo::seal_call_data_load(), - CallDataCopy(len) => T::WeightInfo::seal_call_data_copy(len), - Caller => T::WeightInfo::seal_caller(), - Origin => T::WeightInfo::seal_origin(), - ToAccountId => T::WeightInfo::seal_to_account_id(), - CodeHash => T::WeightInfo::seal_code_hash(), - CodeSize => T::WeightInfo::seal_code_size(), - OwnCodeHash => T::WeightInfo::seal_own_code_hash(), - CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), - CallerIsRoot => T::WeightInfo::seal_caller_is_root(), - Address => T::WeightInfo::seal_address(), - RefTimeLeft => T::WeightInfo::seal_ref_time_left(), - WeightLeft => T::WeightInfo::seal_weight_left(), - Balance => T::WeightInfo::seal_balance(), - BalanceOf => T::WeightInfo::seal_balance_of(), - ValueTransferred => T::WeightInfo::seal_value_transferred(), - MinimumBalance => T::WeightInfo::seal_minimum_balance(), - BlockNumber => T::WeightInfo::seal_block_number(), - BlockHash => T::WeightInfo::seal_block_hash(), - BlockAuthor => T::WeightInfo::seal_block_author(), - GasPrice => T::WeightInfo::seal_gas_price(), - BaseFee => T::WeightInfo::seal_base_fee(), - Now => T::WeightInfo::seal_now(), - GasLimit => T::WeightInfo::seal_gas_limit(), - WeightToFee => T::WeightInfo::seal_weight_to_fee(), - Terminate => T::WeightInfo::seal_terminate(), - DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len), - SetStorage { new_bytes, old_bytes } => { - cost_storage!(write, seal_set_storage, new_bytes, old_bytes) - }, - ClearStorage(len) => cost_storage!(write, seal_clear_storage, len), - ContainsStorage(len) => cost_storage!(read, seal_contains_storage, len), - GetStorage(len) => cost_storage!(read, seal_get_storage, len), - TakeStorage(len) => cost_storage!(write, seal_take_storage, len), - SetTransientStorage { new_bytes, old_bytes } => { - cost_storage!(write_transient, seal_set_transient_storage, new_bytes, old_bytes) - }, - ClearTransientStorage(len) => { - cost_storage!(write_transient, seal_clear_transient_storage, len) - }, - ContainsTransientStorage(len) => { - cost_storage!(read_transient, seal_contains_transient_storage, len) - }, - GetTransientStorage(len) => { - cost_storage!(read_transient, seal_get_transient_storage, len) - }, - TakeTransientStorage(len) => { - cost_storage!(write_transient, seal_take_transient_storage, len) - }, - CallBase => T::WeightInfo::seal_call(0, 0, 0), - DelegateCallBase => T::WeightInfo::seal_delegate_call(), - PrecompileBase => T::WeightInfo::seal_call_precompile(0, 0), - PrecompileWithInfoBase => T::WeightInfo::seal_call_precompile(1, 0), - PrecompileDecode(len) => cost_args!(seal_call_precompile, 0, len), - CallTransferSurcharge { dust_transfer } => - cost_args!(seal_call, 1, dust_transfer.into(), 0), - CallInputCloned(len) => cost_args!(seal_call, 0, 0, len), - Instantiate { input_data_len, balance_transfer, dust_transfer } => - T::WeightInfo::seal_instantiate( - input_data_len, - balance_transfer.into(), - dust_transfer.into(), - ), - HashSha256(len) => T::WeightInfo::sha2_256(len), - Ripemd160(len) => T::WeightInfo::ripemd_160(len), - HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len), - HashBlake256(len) => T::WeightInfo::hash_blake2_256(len), - HashBlake128(len) => T::WeightInfo::hash_blake2_128(len), - EcdsaRecovery => T::WeightInfo::ecdsa_recover(), - Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len), - Precompile(weight) => weight, - SetCodeHash => T::WeightInfo::seal_set_code_hash(), - EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(), - GetImmutableData(len) => T::WeightInfo::seal_get_immutable_data(len), - SetImmutableData(len) => T::WeightInfo::seal_set_immutable_data(len), - Bn128Add => T::WeightInfo::bn128_add(), - Bn128Mul => T::WeightInfo::bn128_mul(), - Bn128Pairing(len) => T::WeightInfo::bn128_pairing(len), - Identity(len) => T::WeightInfo::identity(len), - Blake2F(rounds) => T::WeightInfo::blake2f(rounds), - Modexp(gas) => { - use frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND; - /// Current approximation of the gas/s consumption considering - /// EVM execution over compiled WASM (on 4.4Ghz CPU). - /// Given the 2000ms Weight, from which 75% only are used for transactions, - /// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. - const GAS_PER_SECOND: u64 = 40_000_000; - - /// Approximate ratio of the amount of Weight per Gas. - /// u64 works for approximations because Weight is a very small unit compared to - /// gas. - const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; - Weight::from_parts(gas.saturating_mul(WEIGHT_PER_GAS), 0) - }, - } - } -} - -/// Same as [`Runtime::charge_gas`]. -/// -/// We need this access as a macro because sometimes hiding the lifetimes behind -/// a function won't work out. -macro_rules! charge_gas { - ($runtime:expr, $costs:expr) => {{ - $runtime.ext.gas_meter_mut().charge($costs) - }}; -} - -/// The kind of call that should be performed. -enum CallType { - /// Execute another instantiated contract - Call { value_ptr: u32 }, - /// Execute another contract code in the context (storage, account ID, value) of the caller - /// contract - DelegateCall, -} - -impl CallType { - fn cost(&self) -> RuntimeCosts { - match self { - CallType::Call { .. } => RuntimeCosts::CallBase, - CallType::DelegateCall => RuntimeCosts::DelegateCallBase, - } - } -} - -/// This is only appropriate when writing out data of constant size that does not depend on user -/// input. In this case the costs for this copy was already charged as part of the token at -/// the beginning of the API entry point. -fn already_charged(_: u32) -> Option { - None -} - -/// Helper to extract two `u32` values from a given `u64` register. -fn extract_hi_lo(reg: u64) -> (u32, u32) { - ((reg >> 32) as u32, reg as u32) -} - -/// Provides storage variants to support standard and Etheruem compatible semantics. -enum StorageValue { - /// Indicates that the storage value should be read from a memory buffer. - /// - `ptr`: A pointer to the start of the data in sandbox memory. - /// - `len`: The length (in bytes) of the data. - Memory { ptr: u32, len: u32 }, - - /// Indicates that the storage value is provided inline as a fixed-size (256-bit) value. - /// This is used by set_storage_or_clear() to avoid double reads. - /// This variant is used to implement Ethereum SSTORE-like semantics. - Value(Vec), -} - -/// Controls the output behavior for storage reads, both when a key is found and when it is not. -enum StorageReadMode { - /// VariableOutput mode: if the key exists, the full stored value is returned - /// using the caller‑provided output length. - VariableOutput { output_len_ptr: u32 }, - /// Ethereum commpatible(FixedOutput32) mode: always write a 32-byte value into the output - /// buffer. If the key is missing, write 32 bytes of zeros. - FixedOutput32, -} - -/// Can only be used for one call. -pub struct Runtime<'a, E: Ext, M: ?Sized> { - ext: &'a mut E, - input_data: Option>, - _phantom_data: PhantomData, -} - -impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { - pub fn handle_interrupt( - &mut self, - interrupt: Result, - module: &polkavm::Module, - instance: &mut M, - ) -> Option { - use polkavm::InterruptKind::*; - - match interrupt { - Err(error) => { - // in contrast to the other returns this "should" not happen: log level error - log::error!(target: LOG_TARGET, "polkavm execution error: {error}"); - Some(Err(Error::::ExecutionFailed.into())) - }, - Ok(Finished) => - Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })), - Ok(Trap) => Some(Err(Error::::ContractTrapped.into())), - Ok(Segfault(_)) => Some(Err(Error::::ExecutionFailed.into())), - Ok(NotEnoughGas) => Some(Err(Error::::OutOfGas.into())), - Ok(Step) => None, - Ok(Ecalli(idx)) => { - // This is a special hard coded syscall index which is used by benchmarks - // to abort contract execution. It is used to terminate the execution without - // breaking up a basic block. The fixed index is used so that the benchmarks - // don't have to deal with import tables. - if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL { - return Some(Ok(ExecReturnValue { - flags: ReturnFlags::empty(), - data: Vec::new(), - })) - } - let Some(syscall_symbol) = module.imports().get(idx) else { - return Some(Err(>::InvalidSyscall.into())); - }; - match self.handle_ecall(instance, syscall_symbol.as_bytes()) { - Ok(None) => None, - Ok(Some(return_value)) => { - instance.write_output(return_value); - None - }, - Err(TrapReason::Return(ReturnData { flags, data })) => - match ReturnFlags::from_bits(flags) { - None => Some(Err(Error::::InvalidCallFlags.into())), - Some(flags) => Some(Ok(ExecReturnValue { flags, data })), - }, - Err(TrapReason::Termination) => Some(Ok(Default::default())), - Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())), - } - }, - } - } -} - -impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { - pub fn new(ext: &'a mut E, input_data: Vec) -> Self { - Self { ext, input_data: Some(input_data), _phantom_data: Default::default() } - } - - /// Get a mutable reference to the inner `Ext`. - pub fn ext(&mut self) -> &mut E { - self.ext - } - - /// Charge the gas meter with the specified token. - /// - /// Returns `Err(HostError)` if there is not enough gas. - fn charge_gas(&mut self, costs: RuntimeCosts) -> Result { - charge_gas!(self, costs) - } - - /// Adjust a previously charged amount down to its actual amount. - /// - /// This is when a maximum a priori amount was charged and then should be partially - /// refunded to match the actual amount. - fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) { - self.ext.gas_meter_mut().adjust_gas(charged, actual_costs); - } - - /// Write the given buffer and its length to the designated locations in sandbox memory and - /// charge gas according to the token returned by `create_token`. - /// - /// `out_ptr` is the location in sandbox memory where `buf` should be written to. - /// `out_len_ptr` is an in-out location in sandbox memory. It is read to determine the - /// length of the buffer located at `out_ptr`. If that buffer is smaller than the actual - /// `buf.len()`, only what fits into that buffer is written to `out_ptr`. - /// The actual amount of bytes copied to `out_ptr` is written to `out_len_ptr`. - /// - /// If `out_ptr` is set to the sentinel value of `SENTINEL` and `allow_skip` is true the - /// operation is skipped and `Ok` is returned. This is supposed to help callers to make copying - /// output optional. For example to skip copying back the output buffer of an `seal_call` - /// when the caller is not interested in the result. - /// - /// `create_token` can optionally instruct this function to charge the gas meter with the token - /// it returns. `create_token` receives the variable amount of bytes that are about to be copied - /// by this function. - /// - /// In addition to the error conditions of `Memory::write` this functions returns - /// `Err` if the size of the buffer located at `out_ptr` is too small to fit `buf`. - pub fn write_sandbox_output( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - buf: &[u8], - allow_skip: bool, - create_token: impl FnOnce(u32) -> Option, - ) -> Result<(), DispatchError> { - if allow_skip && out_ptr == SENTINEL { - return Ok(()); - } - - let len = memory.read_u32(out_len_ptr)?; - let buf_len = len.min(buf.len() as u32); - - if let Some(costs) = create_token(buf_len) { - self.charge_gas(costs)?; - } - - memory.write(out_ptr, &buf[..buf_len as usize])?; - memory.write(out_len_ptr, &buf_len.encode()) - } - - /// Same as `write_sandbox_output` but for static size output. - pub fn write_fixed_sandbox_output( - &mut self, - memory: &mut M, - out_ptr: u32, - buf: &[u8], - allow_skip: bool, - create_token: impl FnOnce(u32) -> Option, - ) -> Result<(), DispatchError> { - if buf.is_empty() || (allow_skip && out_ptr == SENTINEL) { - return Ok(()); - } - - let buf_len = buf.len() as u32; - if let Some(costs) = create_token(buf_len) { - self.charge_gas(costs)?; - } - - memory.write(out_ptr, buf) - } - - /// Computes the given hash function on the supplied input. - /// - /// Reads from the sandboxed input buffer into an intermediate buffer. - /// Returns the result directly to the output buffer of the sandboxed memory. - /// - /// It is the callers responsibility to provide an output buffer that - /// is large enough to hold the expected amount of bytes returned by the - /// chosen hash function. - /// - /// # Note - /// - /// The `input` and `output` buffers may overlap. - fn compute_hash_on_intermediate_buffer( - &self, - memory: &mut M, - hash_fn: F, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), DispatchError> - where - F: FnOnce(&[u8]) -> R, - R: AsRef<[u8]>, - { - // Copy input into supervisor memory. - let input = memory.read(input_ptr, input_len)?; - // Compute the hash on the input buffer using the given hash function. - let hash = hash_fn(&input); - // Write the resulting hash back into the sandboxed output buffer. - memory.write(output_ptr, hash.as_ref())?; - Ok(()) - } - - /// Fallible conversion of a `ExecError` to `ReturnErrorCode`. - /// - /// This is used when converting the error returned from a subcall in order to decide - /// whether to trap the caller or allow handling of the error. - fn exec_error_into_return_code(from: ExecError) -> Result { - use crate::exec::ErrorOrigin::Callee; - use ReturnErrorCode::*; - - let transfer_failed = Error::::TransferFailed.into(); - let out_of_gas = Error::::OutOfGas.into(); - let out_of_deposit = Error::::StorageDepositLimitExhausted.into(); - let duplicate_contract = Error::::DuplicateContract.into(); - let unsupported_precompile = Error::::UnsupportedPrecompileAddress.into(); - - // errors in the callee do not trap the caller - match (from.error, from.origin) { - (err, _) if err == transfer_failed => Ok(TransferFailed), - (err, _) if err == duplicate_contract => Ok(DuplicateContractAddress), - (err, _) if err == unsupported_precompile => Err(err), - (err, Callee) if err == out_of_gas || err == out_of_deposit => Ok(OutOfResources), - (_, Callee) => Ok(CalleeTrapped), - (err, _) => Err(err), - } - } - - fn decode_key(&self, memory: &M, key_ptr: u32, key_len: u32) -> Result { - let res = match key_len { - SENTINEL => { - let mut buffer = [0u8; 32]; - memory.read_into_buf(key_ptr, buffer.as_mut())?; - Ok(Key::from_fixed(buffer)) - }, - len => { - ensure!(len <= limits::STORAGE_KEY_BYTES, Error::::DecodingFailed); - let key = memory.read(key_ptr, len)?; - Key::try_from_var(key) - }, - }; - - res.map_err(|_| Error::::DecodingFailed.into()) - } - - fn is_transient(flags: u32) -> Result { - StorageFlags::from_bits(flags) - .ok_or_else(|| >::InvalidStorageFlags.into()) - .map(|flags| flags.contains(StorageFlags::TRANSIENT)) - } - - fn set_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - value: StorageValue, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |new_bytes: u32, old_bytes: u32| { - if transient { - RuntimeCosts::SetTransientStorage { new_bytes, old_bytes } - } else { - RuntimeCosts::SetStorage { new_bytes, old_bytes } - } - }; - - let value_len = match &value { - StorageValue::Memory { ptr: _, len } => *len, - StorageValue::Value(data) => data.len() as u32, - }; - - let max_size = self.ext.max_value_size(); - let charged = self.charge_gas(costs(value_len, self.ext.max_value_size()))?; - if value_len > max_size { - return Err(Error::::ValueTooLarge.into()); - } - - let key = self.decode_key(memory, key_ptr, key_len)?; - - let value = match value { - StorageValue::Memory { ptr, len } => Some(memory.read(ptr, len)?), - StorageValue::Value(data) => Some(data), - }; - - let write_outcome = if transient { - self.ext.set_transient_storage(&key, value, false)? - } else { - self.ext.set_storage(&key, value, false)? - }; - - self.adjust_gas(charged, costs(value_len, write_outcome.old_len())); - Ok(write_outcome.old_len_with_sentinel()) - } - - fn clear_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::ClearTransientStorage(len) - } else { - RuntimeCosts::ClearStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.set_transient_storage(&key, None, false)? - } else { - self.ext.set_storage(&key, None, false)? - }; - self.adjust_gas(charged, costs(outcome.old_len())); - Ok(outcome.old_len_with_sentinel()) - } - - fn get_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - read_mode: StorageReadMode, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::GetTransientStorage(len) - } else { - RuntimeCosts::GetStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.get_transient_storage(&key) - } else { - self.ext.get_storage(&key) - }; - - if let Some(value) = outcome { - self.adjust_gas(charged, costs(value.len() as u32)); - - match read_mode { - StorageReadMode::FixedOutput32 => { - let mut fixed_output = [0u8; 32]; - let len = value.len().min(fixed_output.len()); - fixed_output[..len].copy_from_slice(&value[..len]); - - self.write_fixed_sandbox_output( - memory, - out_ptr, - &fixed_output, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr } => { - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &value, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - } - } else { - self.adjust_gas(charged, costs(0)); - - match read_mode { - StorageReadMode::FixedOutput32 => { - self.write_fixed_sandbox_output( - memory, - out_ptr, - &[0u8; 32], - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - StorageReadMode::VariableOutput { .. } => Ok(ReturnErrorCode::KeyNotFound), - } - } - } - - fn contains_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::ContainsTransientStorage(len) - } else { - RuntimeCosts::ContainsStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.get_transient_storage_size(&key) - } else { - self.ext.get_storage_size(&key) - }; - self.adjust_gas(charged, costs(outcome.unwrap_or(0))); - Ok(outcome.unwrap_or(SENTINEL)) - } - - fn take_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::TakeTransientStorage(len) - } else { - RuntimeCosts::TakeStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.set_transient_storage(&key, None, true)? - } else { - self.ext.set_storage(&key, None, true)? - }; - - if let crate::storage::WriteOutcome::Taken(value) = outcome { - self.adjust_gas(charged, costs(value.len() as u32)); - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &value, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - } else { - self.adjust_gas(charged, costs(0)); - Ok(ReturnErrorCode::KeyNotFound) - } - } - - fn call( - &mut self, - memory: &mut M, - flags: CallFlags, - call_type: CallType, - callee_ptr: u32, - deposit_ptr: u32, - weight: Weight, - input_data_ptr: u32, - input_data_len: u32, - output_ptr: u32, - output_len_ptr: u32, - ) -> Result { - let callee = memory.read_h160(callee_ptr)?; - let precompile = >::get::(&callee.as_fixed_bytes()); - match &precompile { - Some(precompile) if precompile.has_contract_info() => - self.charge_gas(RuntimeCosts::PrecompileWithInfoBase)?, - Some(_) => self.charge_gas(RuntimeCosts::PrecompileBase)?, - None => self.charge_gas(call_type.cost())?, - }; - - let deposit_limit = memory.read_u256(deposit_ptr)?; - - // we do check this in exec.rs but we want to error out early - if input_data_len > limits::CALLDATA_BYTES { - Err(>::CallDataTooLarge)?; - } - - let input_data = if flags.contains(CallFlags::CLONE_INPUT) { - let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; - charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; - input.clone() - } else if flags.contains(CallFlags::FORWARD_INPUT) { - self.input_data.take().ok_or(Error::::InputForwarded)? - } else { - if precompile.is_some() { - self.charge_gas(RuntimeCosts::PrecompileDecode(input_data_len))?; - } else { - self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; - } - memory.read(input_data_ptr, input_data_len)? - }; - - memory.reset_interpreter_cache(); - - let call_outcome = match call_type { - CallType::Call { value_ptr } => { - let read_only = flags.contains(CallFlags::READ_ONLY); - let value = memory.read_u256(value_ptr)?; - if value > 0u32.into() { - // If the call value is non-zero and state change is not allowed, issue an - // error. - if read_only || self.ext.is_read_only() { - return Err(Error::::StateChangeDenied.into()); - } - - self.charge_gas(RuntimeCosts::CallTransferSurcharge { - dust_transfer: Pallet::::has_dust(value), - })?; - } - self.ext.call( - weight, - deposit_limit, - &callee, - value, - input_data, - flags.contains(CallFlags::ALLOW_REENTRY), - read_only, - ) - }, - CallType::DelegateCall => { - if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) { - return Err(Error::::InvalidCallFlags.into()); - } - self.ext.delegate_call(weight, deposit_limit, callee, input_data) - }, - }; - - match call_outcome { - // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to - // a halt anyways without anymore code being executed. - Ok(_) if flags.contains(CallFlags::TAIL_CALL) => { - let output = mem::take(self.ext.last_frame_output_mut()); - return Err(TrapReason::Return(ReturnData { - flags: output.flags.bits(), - data: output.data, - })); - }, - Ok(_) => { - let output = mem::take(self.ext.last_frame_output_mut()); - let write_result = self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - ); - *self.ext.last_frame_output_mut() = output; - write_result?; - Ok(self.ext.last_frame_output().into()) - }, - Err(err) => { - let error_code = Self::exec_error_into_return_code(err)?; - memory.write(output_len_ptr, &0u32.to_le_bytes())?; - Ok(error_code) - }, - } - } - - fn instantiate( - &mut self, - memory: &mut M, - code_hash_ptr: u32, - weight: Weight, - deposit_ptr: u32, - value_ptr: u32, - input_data_ptr: u32, - input_data_len: u32, - address_ptr: u32, - output_ptr: u32, - output_len_ptr: u32, - salt_ptr: u32, - ) -> Result { - let value = match memory.read_u256(value_ptr) { - Ok(value) => { - self.charge_gas(RuntimeCosts::Instantiate { - input_data_len, - balance_transfer: Pallet::::has_balance(value), - dust_transfer: Pallet::::has_dust(value), - })?; - value - }, - Err(err) => { - self.charge_gas(RuntimeCosts::Instantiate { - input_data_len: 0, - balance_transfer: false, - dust_transfer: false, - })?; - return Err(err.into()); - }, - }; - let deposit_limit: U256 = memory.read_u256(deposit_ptr)?; - let code_hash = memory.read_h256(code_hash_ptr)?; - if input_data_len > limits::CALLDATA_BYTES { - Err(>::CallDataTooLarge)?; - } - let input_data = memory.read(input_data_ptr, input_data_len)?; - let salt = if salt_ptr == SENTINEL { - None - } else { - let salt: [u8; 32] = memory.read_array(salt_ptr)?; - Some(salt) - }; - - memory.reset_interpreter_cache(); - - match self.ext.instantiate( - weight, - deposit_limit, - code_hash, - value, - input_data, - salt.as_ref(), - ) { - Ok(address) => { - if !self.ext.last_frame_output().flags.contains(ReturnFlags::REVERT) { - self.write_fixed_sandbox_output( - memory, - address_ptr, - &address.as_bytes(), - true, - already_charged, - )?; - } - let output = mem::take(self.ext.last_frame_output_mut()); - let write_result = self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - ); - *self.ext.last_frame_output_mut() = output; - write_result?; - Ok(self.ext.last_frame_output().into()) - }, - Err(err) => Ok(Self::exec_error_into_return_code(err)?), - } - } -} - -// This is the API exposed to contracts. -// -// # Note -// -// Any input that leads to a out of bound error (reading or writing) or failing to decode -// data passed to the supervisor will lead to a trap. This is not documented explicitly -// for every function. -#[define_env] -pub mod env { - /// Noop function used to benchmark the time it takes to execute an empty function. - /// - /// Marked as stable because it needs to be called from benchmarks even when the benchmarked - /// parachain has unstable functions disabled. - #[cfg(feature = "runtime-benchmarks")] - #[stable] - fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> { - Ok(()) - } - - /// Set the value at the given key in the contract storage. - /// See [`pallet_revive_uapi::HostFn::set_storage_v2`] - #[stable] - #[mutating] - fn set_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - value_ptr: u32, - value_len: u32, - ) -> Result { - self.set_storage( - memory, - flags, - key_ptr, - key_len, - StorageValue::Memory { ptr: value_ptr, len: value_len }, - ) - } - - /// Sets the storage at a fixed 256-bit key with a fixed 256-bit value. - /// See [`pallet_revive_uapi::HostFn::set_storage_or_clear`]. - #[stable] - #[mutating] - fn set_storage_or_clear( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - value_ptr: u32, - ) -> Result { - let value = memory.read(value_ptr, 32)?; - - if value.iter().all(|&b| b == 0) { - self.clear_storage(memory, flags, key_ptr, SENTINEL) - } else { - self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value)) - } - } - - /// Retrieve the value under the given key from storage. - /// See [`pallet_revive_uapi::HostFn::get_storage`] - #[stable] - fn get_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - self.get_storage( - memory, - flags, - key_ptr, - key_len, - out_ptr, - StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr }, - ) - } - - /// Reads the storage at a fixed 256-bit key and writes back a fixed 256-bit value. - /// See [`pallet_revive_uapi::HostFn::get_storage_or_zero`]. - #[stable] - fn get_storage_or_zero( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - let _ = self.get_storage( - memory, - flags, - key_ptr, - SENTINEL, - out_ptr, - StorageReadMode::FixedOutput32, - )?; - - Ok(()) - } - - /// Make a call to another contract. - /// See [`pallet_revive_uapi::HostFn::call`]. - #[stable] - fn call( - &mut self, - memory: &mut M, - flags_and_callee: u64, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_and_value: u64, - input_data: u64, - output_data: u64, - ) -> Result { - let (flags, callee_ptr) = extract_hi_lo(flags_and_callee); - let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); - let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - - self.call( - memory, - CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::Call { value_ptr }, - callee_ptr, - deposit_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - input_data_ptr, - input_data_len, - output_ptr, - output_len_ptr, - ) - } - - /// Execute code in the context (storage, caller, value) of the current contract. - /// See [`pallet_revive_uapi::HostFn::delegate_call`]. - #[stable] - fn delegate_call( - &mut self, - memory: &mut M, - flags_and_callee: u64, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_ptr: u32, - input_data: u64, - output_data: u64, - ) -> Result { - let (flags, address_ptr) = extract_hi_lo(flags_and_callee); - let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - - self.call( - memory, - CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::DelegateCall, - address_ptr, - deposit_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - input_data_ptr, - input_data_len, - output_ptr, - output_len_ptr, - ) - } - - /// Instantiate a contract with the specified code hash. - /// See [`pallet_revive_uapi::HostFn::instantiate`]. - #[stable] - #[mutating] - fn instantiate( - &mut self, - memory: &mut M, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_and_value: u64, - input_data: u64, - output_data: u64, - address_and_salt: u64, - ) -> Result { - let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); - let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt); - let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else { - return Err(Error::::OutOfBounds.into()); - }; - let Some(input_data_len) = input_data_len.checked_sub(32) else { - return Err(Error::::OutOfBounds.into()); - }; - - self.instantiate( - memory, - code_hash_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - deposit_ptr, - value_ptr, - input_data_ptr, - input_data_len, - address_ptr, - output_ptr, - output_len_ptr, - salt_ptr, - ) - } - - /// Returns the total size of the contract call input data. - /// See [`pallet_revive_uapi::HostFn::call_data_size `]. - #[stable] - fn call_data_size(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallDataSize)?; - Ok(self - .input_data - .as_ref() - .map(|input| input.len().try_into().expect("usize fits into u64; qed")) - .unwrap_or_default()) - } - - /// Stores the input passed by the caller into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::call_data_copy`]. - #[stable] - fn call_data_copy( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len: u32, - offset: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?; - - let Some(input) = self.input_data.as_ref() else { - return Err(Error::::InputForwarded.into()); - }; - - let start = offset as usize; - if start >= input.len() { - memory.zero(out_ptr, out_len)?; - return Ok(()); - } - - let end = start.saturating_add(out_len as usize).min(input.len()); - memory.write(out_ptr, &input[start..end])?; - - let bytes_written = (end - start) as u32; - memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?; - - Ok(()) - } - - /// Stores the U256 value at given call input `offset` into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::call_data_load`]. - #[stable] - fn call_data_load( - &mut self, - memory: &mut M, - out_ptr: u32, - offset: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CallDataLoad)?; - - let Some(input) = self.input_data.as_ref() else { - return Err(Error::::InputForwarded.into()); - }; - - let mut data = [0; 32]; - let start = offset as usize; - let data = if start >= input.len() { - data // Any index is valid to request; OOB offsets return zero. - } else { - let end = start.saturating_add(32).min(input.len()); - data[..end - start].copy_from_slice(&input[start..end]); - data.reverse(); - data // Solidity expects right-padded data - }; - - self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?; - - Ok(()) - } - - /// Cease contract execution and save a data buffer as a result of the execution. - /// See [`pallet_revive_uapi::HostFn::return_value`]. - #[stable] - fn seal_return( - &mut self, - memory: &mut M, - flags: u32, - data_ptr: u32, - data_len: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?; - if data_len > limits::CALLDATA_BYTES { - Err(>::ReturnDataTooLarge)?; - } - Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? })) - } - - /// Stores the address of the caller into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::caller`]. - #[stable] - fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Caller)?; - let caller = ::AddressMapper::to_address(self.ext.caller().account_id()?); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - caller.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the address of the call stack origin into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::origin`]. - #[stable] - fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Origin)?; - let origin = ::AddressMapper::to_address(self.ext.origin().account_id()?); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - origin.as_bytes(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash for a specified contract address. - /// See [`pallet_revive_uapi::HostFn::code_hash`]. - #[stable] - fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CodeHash)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.code_hash(&address).as_bytes(), - false, - already_charged, - )?) - } - - /// Retrieve the code size for a given contract address. - /// See [`pallet_revive_uapi::HostFn::code_size`]. - #[stable] - fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result { - self.charge_gas(RuntimeCosts::CodeSize)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.ext.code_size(&address)) - } - - /// Stores the address of the current contract into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::address`]. - #[stable] - fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Address)?; - let address = self.ext.address(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - address.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the price for the specified amount of weight into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_to_fee`]. - #[stable] - fn weight_to_fee( - &mut self, - memory: &mut M, - ref_time_limit: u64, - proof_size_limit: u64, - out_ptr: u32, - ) -> Result<(), TrapReason> { - let weight = Weight::from_parts(ref_time_limit, proof_size_limit); - self.charge_gas(RuntimeCosts::WeightToFee)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.get_weight_price(weight).encode(), - false, - already_charged, - )?) - } - - /// Stores the immutable data into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. - #[stable] - fn get_immutable_data( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - // quering the length is free as it is stored with the contract metadata - let len = self.ext.immutable_data_len(); - self.charge_gas(RuntimeCosts::GetImmutableData(len))?; - let data = self.ext.get_immutable_data()?; - self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?; - Ok(()) - } - - /// Attaches the supplied immutable data to the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::set_immutable_data`]. - #[stable] - fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { - if len > limits::IMMUTABLE_BYTES { - return Err(Error::::OutOfBounds.into()); - } - self.charge_gas(RuntimeCosts::SetImmutableData(len))?; - let buf = memory.read(ptr, len)?; - let data = buf.try_into().expect("bailed out earlier; qed"); - self.ext.set_immutable_data(data)?; - Ok(()) - } - - /// Stores the *free* balance of the current account into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::balance`]. - #[stable] - fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Balance)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.balance().to_little_endian(), - false, - already_charged, - )?) - } - - /// Stores the *free* balance of the supplied address into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::balance`]. - #[stable] - fn balance_of( - &mut self, - memory: &mut M, - addr_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BalanceOf)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.balance_of(&address).to_little_endian(), - false, - already_charged, - )?) - } - - /// Returns the chain ID. - /// See [`pallet_revive_uapi::HostFn::chain_id`]. - #[stable] - fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &U256::from(::ChainId::get()).to_little_endian(), - false, - |_| Some(RuntimeCosts::CopyToContract(32)), - )?) - } - - /// Returns the block ref_time limit. - /// See [`pallet_revive_uapi::HostFn::gas_limit`]. - #[stable] - fn gas_limit(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::GasLimit)?; - Ok(::BlockWeights::get().max_block.ref_time()) - } - - /// Stores the value transferred along with this call/instantiate into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::value_transferred`]. - #[stable] - fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::ValueTransferred)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.value_transferred().to_little_endian(), - false, - already_charged, - )?) - } - - /// Returns the simulated ethereum `GASPRICE` value. - /// See [`pallet_revive_uapi::HostFn::gas_price`]. - #[stable] - fn gas_price(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::GasPrice)?; - Ok(GAS_PRICE.into()) - } - - /// Returns the simulated ethereum `BASEFEE` value. - /// See [`pallet_revive_uapi::HostFn::base_fee`]. - #[stable] - fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BaseFee)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &U256::zero().to_little_endian(), - false, - already_charged, - )?) - } - - /// Load the latest block timestamp into the supplied buffer - /// See [`pallet_revive_uapi::HostFn::now`]. - #[stable] - fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Now)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.now().to_little_endian(), - false, - already_charged, - )?) - } - - /// Deposit a contract event with the data buffer and optional list of topics. - /// See [pallet_revive_uapi::HostFn::deposit_event] - #[stable] - #[mutating] - fn deposit_event( - &mut self, - memory: &mut M, - topics_ptr: u32, - num_topic: u32, - data_ptr: u32, - data_len: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?; - - if num_topic > limits::NUM_EVENT_TOPICS { - return Err(Error::::TooManyTopics.into()); - } - - if data_len > self.ext.max_value_size() { - return Err(Error::::ValueTooLarge.into()); - } - - let topics: Vec = match num_topic { - 0 => Vec::new(), - _ => { - let mut v = Vec::with_capacity(num_topic as usize); - let topics_len = num_topic * H256::len_bytes() as u32; - let buf = memory.read(topics_ptr, topics_len)?; - for chunk in buf.chunks_exact(H256::len_bytes()) { - v.push(H256::from_slice(chunk)); - } - v - }, - }; - - let event_data = memory.read(data_ptr, data_len)?; - self.ext.deposit_event(topics, event_data); - Ok(()) - } - - /// Stores the current block number of the current contract into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_number`]. - #[stable] - fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockNumber)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.block_number().to_little_endian(), - false, - already_charged, - )?) - } - - /// Stores the block hash at given block height into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_hash`]. - #[stable] - fn block_hash( - &mut self, - memory: &mut M, - block_number_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockHash)?; - let block_number = memory.read_u256(block_number_ptr)?; - let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero()); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &block_hash.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the current block author into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_author`]. - #[stable] - fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockAuthor)?; - let block_author = self.ext.block_author().unwrap_or(H160::zero()); - - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &block_author.as_bytes(), - false, - already_charged, - )?) - } - - /// Computes the KECCAK 256-bit hash on the given input buffer. - /// See [`pallet_revive_uapi::HostFn::hash_keccak_256`]. - #[stable] - fn hash_keccak_256( - &mut self, - memory: &mut M, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; - Ok(self.compute_hash_on_intermediate_buffer( - memory, keccak_256, input_ptr, input_len, output_ptr, - )?) - } - - /// Stores the length of the data returned by the last call into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::return_data_size`]. - #[stable] - fn return_data_size(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::ReturnDataSize)?; - Ok(self - .ext - .last_frame_output() - .data - .len() - .try_into() - .expect("usize fits into u64; qed")) - } - - /// Stores data returned by the last call, starting from `offset`, into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::return_data`]. - #[stable] - fn return_data_copy( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - offset: u32, - ) -> Result<(), TrapReason> { - let output = mem::take(self.ext.last_frame_output_mut()); - let result = if offset as usize > output.data.len() { - Err(Error::::OutOfBounds.into()) - } else { - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &output.data[offset as usize..], - false, - |len| Some(RuntimeCosts::CopyToContract(len)), - ) - }; - *self.ext.last_frame_output_mut() = output; - Ok(result?) - } - - /// Returns the amount of ref_time left. - /// See [`pallet_revive_uapi::HostFn::ref_time_left`]. - #[stable] - fn ref_time_left(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::RefTimeLeft)?; - Ok(self.ext.gas_meter().gas_left().ref_time()) - } - - /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. - fn caller_is_origin(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsOrigin)?; - Ok(self.ext.caller_is_origin() as u32) - } - - /// Checks whether the caller of the current contract is root. - /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. - fn caller_is_root(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsRoot)?; - Ok(self.ext.caller_is_root() as u32) - } - - /// Clear the value at the given key in the contract storage. - /// See [`pallet_revive_uapi::HostFn::clear_storage`] - #[mutating] - fn clear_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.clear_storage(memory, flags, key_ptr, key_len) - } - - /// Checks whether there is a value stored under the given key. - /// See [`pallet_revive_uapi::HostFn::contains_storage`] - fn contains_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.contains_storage(memory, flags, key_ptr, key_len) - } - - /// Calculates Ethereum address from the ECDSA compressed public key and stores - /// See [`pallet_revive_uapi::HostFn::ecdsa_to_eth_address`]. - fn ecdsa_to_eth_address( - &mut self, - memory: &mut M, - key_ptr: u32, - out_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; - let mut compressed_key: [u8; 33] = [0; 33]; - memory.read_into_buf(key_ptr, &mut compressed_key)?; - let result = self.ext.ecdsa_to_eth_address(&compressed_key); - match result { - Ok(eth_address) => { - memory.write(out_ptr, eth_address.as_ref())?; - Ok(ReturnErrorCode::Success) - }, - Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed), - } - } - - /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. - fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::MinimumBalance)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.minimum_balance().to_little_endian(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash of the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. - fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::OwnCodeHash)?; - let code_hash = *self.ext.own_code_hash(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - code_hash.as_bytes(), - false, - already_charged, - )?) - } - - /// Replace the contract code at the specified address with new code. - /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. - /// - /// Disabled until the internal implementation takes care of collecting - /// the immutable data of the new code hash. - #[mutating] - fn set_code_hash(&mut self, memory: &mut M, code_hash_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::SetCodeHash)?; - let code_hash: H256 = memory.read_h256(code_hash_ptr)?; - self.ext.set_code_hash(code_hash)?; - Ok(()) - } - - /// Verify a sr25519 signature - /// See [`pallet_revive_uapi::HostFn::sr25519_verify`]. - fn sr25519_verify( - &mut self, - memory: &mut M, - signature_ptr: u32, - pub_key_ptr: u32, - message_len: u32, - message_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; - - let mut signature: [u8; 64] = [0; 64]; - memory.read_into_buf(signature_ptr, &mut signature)?; - - let mut pub_key: [u8; 32] = [0; 32]; - memory.read_into_buf(pub_key_ptr, &mut pub_key)?; - - let message: Vec = memory.read(message_ptr, message_len)?; - - if self.ext.sr25519_verify(&signature, &message, &pub_key) { - Ok(ReturnErrorCode::Success) - } else { - Ok(ReturnErrorCode::Sr25519VerifyFailed) - } - } - - /// Retrieve and remove the value under the given key from storage. - /// See [`pallet_revive_uapi::HostFn::take_storage`] - #[mutating] - fn take_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) - } - - /// Remove the calling account and transfer remaining **free** balance. - /// See [`pallet_revive_uapi::HostFn::terminate`]. - #[mutating] - fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Terminate)?; - let beneficiary = memory.read_h160(beneficiary_ptr)?; - self.ext.terminate(&beneficiary)?; - Err(TrapReason::Termination) - } - - /// Stores the amount of weight left into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_left`]. - fn weight_left( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::WeightLeft)?; - let gas_left = &self.ext.gas_meter().gas_left().encode(); - Ok(self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - gas_left, - false, - already_charged, - )?) - } -} diff --git a/substrate/frame/revive/src/vm/runtime_costs.rs b/substrate/frame/revive/src/vm/runtime_costs.rs new file mode 100644 index 0000000000000..7c71a1bb1b933 --- /dev/null +++ b/substrate/frame/revive/src/vm/runtime_costs.rs @@ -0,0 +1,315 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{gas::Token, weights::WeightInfo, Config}; +use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}; + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2000ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to +/// gas. +const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; + +#[cfg_attr(test, derive(Debug, PartialEq, Eq))] +#[derive(Copy, Clone)] +pub enum RuntimeCosts { + /// Base Weight of calling a host function. + HostFn, + /// Weight charged for copying data from the sandbox. + CopyFromContract(u32), + /// Weight charged for copying data to the sandbox. + CopyToContract(u32), + /// Weight of calling `seal_call_data_load``. + CallDataLoad, + /// Weight of calling `seal_call_data_copy`. + CallDataCopy(u32), + /// Weight of calling `seal_caller`. + Caller, + /// Weight of calling `seal_call_data_size`. + CallDataSize, + /// Weight of calling `seal_return_data_size`. + ReturnDataSize, + /// Weight of calling `seal_to_account_id`. + ToAccountId, + /// Weight of calling `seal_origin`. + Origin, + /// Weight of calling `seal_code_hash`. + CodeHash, + /// Weight of calling `seal_own_code_hash`. + OwnCodeHash, + /// Weight of calling `seal_code_size`. + CodeSize, + /// Weight of calling `seal_caller_is_origin`. + CallerIsOrigin, + /// Weight of calling `caller_is_root`. + CallerIsRoot, + /// Weight of calling `seal_address`. + Address, + /// Weight of calling `seal_ref_time_left`. + RefTimeLeft, + /// Weight of calling `seal_weight_left`. + WeightLeft, + /// Weight of calling `seal_balance`. + Balance, + /// Weight of calling `seal_balance_of`. + BalanceOf, + /// Weight of calling `seal_value_transferred`. + ValueTransferred, + /// Weight of calling `seal_minimum_balance`. + MinimumBalance, + /// Weight of calling `seal_block_number`. + BlockNumber, + /// Weight of calling `seal_block_hash`. + BlockHash, + /// Weight of calling `seal_block_author`. + BlockAuthor, + /// Weight of calling `seal_gas_price`. + GasPrice, + /// Weight of calling `seal_base_fee`. + BaseFee, + /// Weight of calling `seal_now`. + Now, + /// Weight of calling `seal_gas_limit`. + GasLimit, + /// Weight of calling `seal_weight_to_fee`. + WeightToFee, + /// Weight of calling `seal_terminate`. + Terminate, + /// Weight of calling `seal_deposit_event` with the given number of topics and event size. + DepositEvent { num_topic: u32, len: u32 }, + /// Weight of calling `seal_set_storage` for the given storage item sizes. + SetStorage { old_bytes: u32, new_bytes: u32 }, + /// Weight of calling `seal_clear_storage` per cleared byte. + ClearStorage(u32), + /// Weight of calling `seal_contains_storage` per byte of the checked item. + ContainsStorage(u32), + /// Weight of calling `seal_get_storage` with the specified size in storage. + GetStorage(u32), + /// Weight of calling `seal_take_storage` for the given size. + TakeStorage(u32), + /// Weight of calling `seal_set_transient_storage` for the given storage item sizes. + SetTransientStorage { old_bytes: u32, new_bytes: u32 }, + /// Weight of calling `seal_clear_transient_storage` per cleared byte. + ClearTransientStorage(u32), + /// Weight of calling `seal_contains_transient_storage` per byte of the checked item. + ContainsTransientStorage(u32), + /// Weight of calling `seal_get_transient_storage` with the specified size in storage. + GetTransientStorage(u32), + /// Weight of calling `seal_take_transient_storage` for the given size. + TakeTransientStorage(u32), + /// Base weight of calling `seal_call`. + CallBase, + /// Weight of calling `seal_delegate_call` for the given input size. + DelegateCallBase, + /// Weight of calling a precompile. + PrecompileBase, + /// Weight of calling a precompile that has a contract info. + PrecompileWithInfoBase, + /// Weight of reading and decoding the input to a precompile. + PrecompileDecode(u32), + /// Weight of the transfer performed during a call. + /// parameter `dust_transfer` indicates whether the transfer has a `dust` value. + CallTransferSurcharge { dust_transfer: bool }, + /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. + CallInputCloned(u32), + /// Weight of calling `seal_instantiate`. + Instantiate { input_data_len: u32, balance_transfer: bool, dust_transfer: bool }, + /// Weight of calling `Ripemd160` precompile for the given input size. + Ripemd160(u32), + /// Weight of calling `Sha256` precompile for the given input size. + HashSha256(u32), + /// Weight of calling the `System::hashBlake256` precompile function for the given input + HashKeccak256(u32), + /// Weight of calling the `System::hash_blake2_256` precompile function for the given input + /// size. + HashBlake256(u32), + /// Weight of calling `System::hashBlake128` precompile function for the given input size. + HashBlake128(u32), + /// Weight of calling `ECERecover` precompile. + EcdsaRecovery, + /// Weight of calling `seal_sr25519_verify` for the given input size. + Sr25519Verify(u32), + /// Weight charged by a precompile. + Precompile(Weight), + /// Weight of calling `seal_set_code_hash` + SetCodeHash, + /// Weight of calling `ecdsa_to_eth_address` + EcdsaToEthAddress, + /// Weight of calling `get_immutable_dependency` + GetImmutableData(u32), + /// Weight of calling `set_immutable_dependency` + SetImmutableData(u32), + /// Weight of calling `Bn128Add` precompile + Bn128Add, + /// Weight of calling `Bn128Add` precompile + Bn128Mul, + /// Weight of calling `Bn128Pairing` precompile for the given number of input pairs. + Bn128Pairing(u32), + /// Weight of calling `Identity` precompile for the given number of input length. + Identity(u32), + /// Weight of calling `Blake2F` precompile for the given number of rounds. + Blake2F(u32), + /// Weight of calling `Modexp` precompile + Modexp(u64), +} + +/// For functions that modify storage, benchmarks are performed with one item in the +/// storage. To account for the worst-case scenario, the weight of the overhead of +/// writing to or reading from full storage is included. For transient storage writes, +/// the rollback weight is added to reflect the worst-case scenario for this operation. +macro_rules! cost_storage { + (write_transient, $name:ident $(, $arg:expr )*) => { + T::WeightInfo::$name($( $arg ),*) + .saturating_add(T::WeightInfo::rollback_transient_storage()) + .saturating_add(T::WeightInfo::set_transient_storage_full() + .saturating_sub(T::WeightInfo::set_transient_storage_empty())) + }; + + (read_transient, $name:ident $(, $arg:expr )*) => { + T::WeightInfo::$name($( $arg ),*) + .saturating_add(T::WeightInfo::get_transient_storage_full() + .saturating_sub(T::WeightInfo::get_transient_storage_empty())) + }; + + (write, $name:ident $(, $arg:expr )*) => { + T::WeightInfo::$name($( $arg ),*) + .saturating_add(T::WeightInfo::set_storage_full() + .saturating_sub(T::WeightInfo::set_storage_empty())) + }; + + (read, $name:ident $(, $arg:expr )*) => { + T::WeightInfo::$name($( $arg ),*) + .saturating_add(T::WeightInfo::get_storage_full() + .saturating_sub(T::WeightInfo::get_storage_empty())) + }; +} + +macro_rules! cost_args { + // cost_args!(name, a, b, c) -> T::WeightInfo::name(a, b, c).saturating_sub(T::WeightInfo::name(0, 0, 0)) + ($name:ident, $( $arg: expr ),+) => { + (T::WeightInfo::$name($( $arg ),+).saturating_sub(cost_args!(@call_zero $name, $( $arg ),+))) + }; + // Transform T::WeightInfo::name(a, b, c) into T::WeightInfo::name(0, 0, 0) + (@call_zero $name:ident, $( $arg:expr ),*) => { + T::WeightInfo::$name($( cost_args!(@replace_token $arg) ),*) + }; + // Replace the token with 0. + (@replace_token $_in:tt) => { 0 }; +} + +impl Token for RuntimeCosts { + fn influence_lowest_gas_limit(&self) -> bool { + true + } + + fn weight(&self) -> Weight { + use self::RuntimeCosts::*; + match *self { + HostFn => cost_args!(noop_host_fn, 1), + CopyToContract(len) => T::WeightInfo::seal_copy_to_contract(len), + CopyFromContract(len) => T::WeightInfo::seal_return(len), + CallDataSize => T::WeightInfo::seal_call_data_size(), + ReturnDataSize => T::WeightInfo::seal_return_data_size(), + CallDataLoad => T::WeightInfo::seal_call_data_load(), + CallDataCopy(len) => T::WeightInfo::seal_call_data_copy(len), + Caller => T::WeightInfo::seal_caller(), + Origin => T::WeightInfo::seal_origin(), + ToAccountId => T::WeightInfo::seal_to_account_id(), + CodeHash => T::WeightInfo::seal_code_hash(), + CodeSize => T::WeightInfo::seal_code_size(), + OwnCodeHash => T::WeightInfo::seal_own_code_hash(), + CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), + CallerIsRoot => T::WeightInfo::seal_caller_is_root(), + Address => T::WeightInfo::seal_address(), + RefTimeLeft => T::WeightInfo::seal_ref_time_left(), + WeightLeft => T::WeightInfo::seal_weight_left(), + Balance => T::WeightInfo::seal_balance(), + BalanceOf => T::WeightInfo::seal_balance_of(), + ValueTransferred => T::WeightInfo::seal_value_transferred(), + MinimumBalance => T::WeightInfo::seal_minimum_balance(), + BlockNumber => T::WeightInfo::seal_block_number(), + BlockHash => T::WeightInfo::seal_block_hash(), + BlockAuthor => T::WeightInfo::seal_block_author(), + GasPrice => T::WeightInfo::seal_gas_price(), + BaseFee => T::WeightInfo::seal_base_fee(), + Now => T::WeightInfo::seal_now(), + GasLimit => T::WeightInfo::seal_gas_limit(), + WeightToFee => T::WeightInfo::seal_weight_to_fee(), + Terminate => T::WeightInfo::seal_terminate(), + DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len), + SetStorage { new_bytes, old_bytes } => { + cost_storage!(write, seal_set_storage, new_bytes, old_bytes) + }, + ClearStorage(len) => cost_storage!(write, seal_clear_storage, len), + ContainsStorage(len) => cost_storage!(read, seal_contains_storage, len), + GetStorage(len) => cost_storage!(read, seal_get_storage, len), + TakeStorage(len) => cost_storage!(write, seal_take_storage, len), + SetTransientStorage { new_bytes, old_bytes } => { + cost_storage!(write_transient, seal_set_transient_storage, new_bytes, old_bytes) + }, + ClearTransientStorage(len) => { + cost_storage!(write_transient, seal_clear_transient_storage, len) + }, + ContainsTransientStorage(len) => { + cost_storage!(read_transient, seal_contains_transient_storage, len) + }, + GetTransientStorage(len) => { + cost_storage!(read_transient, seal_get_transient_storage, len) + }, + TakeTransientStorage(len) => { + cost_storage!(write_transient, seal_take_transient_storage, len) + }, + CallBase => T::WeightInfo::seal_call(0, 0, 0), + DelegateCallBase => T::WeightInfo::seal_delegate_call(), + PrecompileBase => T::WeightInfo::seal_call_precompile(0, 0), + PrecompileWithInfoBase => T::WeightInfo::seal_call_precompile(1, 0), + PrecompileDecode(len) => cost_args!(seal_call_precompile, 0, len), + CallTransferSurcharge { dust_transfer } => + cost_args!(seal_call, 1, dust_transfer.into(), 0), + CallInputCloned(len) => cost_args!(seal_call, 0, 0, len), + Instantiate { input_data_len, balance_transfer, dust_transfer } => + T::WeightInfo::seal_instantiate( + input_data_len, + balance_transfer.into(), + dust_transfer.into(), + ), + HashSha256(len) => T::WeightInfo::sha2_256(len), + Ripemd160(len) => T::WeightInfo::ripemd_160(len), + HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len), + HashBlake256(len) => T::WeightInfo::hash_blake2_256(len), + HashBlake128(len) => T::WeightInfo::hash_blake2_128(len), + EcdsaRecovery => T::WeightInfo::ecdsa_recover(), + Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len), + Precompile(weight) => weight, + SetCodeHash => T::WeightInfo::seal_set_code_hash(), + EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(), + GetImmutableData(len) => T::WeightInfo::seal_get_immutable_data(len), + SetImmutableData(len) => T::WeightInfo::seal_set_immutable_data(len), + Bn128Add => T::WeightInfo::bn128_add(), + Bn128Mul => T::WeightInfo::bn128_mul(), + Bn128Pairing(len) => T::WeightInfo::bn128_pairing(len), + Identity(len) => T::WeightInfo::identity(len), + Blake2F(rounds) => T::WeightInfo::blake2f(rounds), + Modexp(gas) => Weight::from_parts(gas.saturating_mul(WEIGHT_PER_GAS), 0), + } + } +} diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 10f9ab7daec3b..2f739f7a7ab2b 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -57,6 +57,7 @@ default = ["std"] std = [ "binary-merkle-tree/std", "codec/std", + "either/std", "either/use_std", "hash256-std-hasher/std", "log/std", From aca6b892f8294e0ada5ed83b7696aef477ec1101 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:16:52 +0100 Subject: [PATCH 03/16] Fix `pallet_session` benchmarks (#9504) Fixes the benchmarking code of `pallet_session` such that it works with any `KeyDeposit`. Reported by @bkontur in https://github.com/polkadot-fellows/runtimes/pull/855 --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Branislav Kontur --- .../snowbridge/runtime/test-common/Cargo.toml | 1 + cumulus/pallets/collator-selection/Cargo.toml | 1 + .../collator-selection/src/benchmarking.rs | 6 +- .../pallets/session-benchmarking/Cargo.toml | 1 + .../pallets/session-benchmarking/src/inner.rs | 2 + .../assets/asset-hub-rococo/Cargo.toml | 1 + .../assets/asset-hub-westend/Cargo.toml | 1 + .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 1 + .../bridge-hubs/bridge-hub-westend/Cargo.toml | 1 + .../collectives-westend/Cargo.toml | 1 + .../coretime/coretime-rococo/Cargo.toml | 1 + .../coretime/coretime-westend/Cargo.toml | 1 + .../runtimes/people/people-rococo/Cargo.toml | 1 + .../runtimes/people/people-westend/Cargo.toml | 1 + .../runtimes/testing/penpal/Cargo.toml | 1 + polkadot/runtime/common/Cargo.toml | 1 + polkadot/runtime/parachains/Cargo.toml | 1 + .../src/disputes/slashing/benchmarking.rs | 1 + polkadot/runtime/rococo/Cargo.toml | 1 + polkadot/runtime/test-runtime/Cargo.toml | 1 + polkadot/runtime/westend/Cargo.toml | 1 + polkadot/runtime/westend/src/lib.rs | 3 +- .../westend/src/weights/pallet_session.rs | 36 +++++------ ...ot_runtime_parachains_disputes_slashing.rs | 38 +++++++----- prdoc/pr_9504.prdoc | 62 +++++++++++++++++++ substrate/frame/babe/Cargo.toml | 1 + substrate/frame/beefy-mmr/Cargo.toml | 1 + substrate/frame/grandpa/Cargo.toml | 1 + substrate/frame/im-online/Cargo.toml | 1 + .../frame/offences/benchmarking/Cargo.toml | 1 + .../frame/offences/benchmarking/src/inner.rs | 1 + substrate/frame/root-offences/Cargo.toml | 1 + substrate/frame/session/Cargo.toml | 8 +++ .../frame/session/benchmarking/Cargo.toml | 1 + .../frame/session/benchmarking/src/inner.rs | 7 ++- .../frame/session/benchmarking/src/mock.rs | 4 +- substrate/frame/session/src/lib.rs | 23 ++++++- .../frame/staking-async/ah-client/Cargo.toml | 1 + .../runtimes/parachain/Cargo.toml | 1 + .../staking-async/runtimes/rc/Cargo.toml | 1 + substrate/frame/staking/Cargo.toml | 1 + umbrella/Cargo.toml | 1 + 42 files changed, 181 insertions(+), 40 deletions(-) create mode 100644 prdoc/pr_9504.prdoc diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index a4fd7c9562938..68da8579816ed 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -85,6 +85,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index eef9e701357c9..dd16585b978e7 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -46,6 +46,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index 706695106ba69..5d34641aee758 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -79,6 +79,7 @@ fn register_validators(count: u32) -> Vec(c)).collect::>(); for (who, keys) in validators.clone() { + >::ensure_can_pay_key_deposit(&who).unwrap(); >::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap(); } @@ -158,6 +159,7 @@ mod benchmarks { candidates.push((new_invulnerable.clone(), new_invulnerable_keys)); // set their keys ... for (who, keys) in candidates.clone() { + >::ensure_can_pay_key_deposit(&who).unwrap(); >::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()) .unwrap(); } @@ -298,6 +300,7 @@ mod benchmarks { let bond: BalanceOf = ::Currency::minimum_balance() * 2u32.into(); ::Currency::make_free_balance_be(&caller, bond); + >::ensure_can_pay_key_deposit(&caller).unwrap(); >::set_keys( RawOrigin::Signed(caller.clone()).into(), keys::(c + 1), @@ -325,6 +328,7 @@ mod benchmarks { let bond: BalanceOf = ::Currency::minimum_balance() * 10u32.into(); ::Currency::make_free_balance_be(&caller, bond); + >::ensure_can_pay_key_deposit(&caller).unwrap(); >::set_keys( RawOrigin::Signed(caller.clone()).into(), keys::(c + 1), @@ -456,5 +460,5 @@ mod benchmarks { } } - impl_benchmark_test_suite!(CollatorSelection, crate::mock::new_test_ext(), crate::mock::Test,); + impl_benchmark_test_suite!(CollatorSelection, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index 6d77e567c9b6b..307227ccd6464 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -29,6 +29,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] std = [ diff --git a/cumulus/pallets/session-benchmarking/src/inner.rs b/cumulus/pallets/session-benchmarking/src/inner.rs index 6c5188921362e..be7d7740be6bd 100644 --- a/cumulus/pallets/session-benchmarking/src/inner.rs +++ b/cumulus/pallets/session-benchmarking/src/inner.rs @@ -35,6 +35,7 @@ mod benchmarks { frame_system::Pallet::::inc_providers(&caller); let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0, 1, 2, 3]; + >::ensure_can_pay_key_deposit(&caller).unwrap(); #[extrinsic_call] _(RawOrigin::Signed(caller), keys, proof); @@ -48,6 +49,7 @@ mod benchmarks { frame_system::Pallet::::inc_providers(&caller); let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0, 1, 2, 3]; + >::ensure_can_pay_key_deposit(&caller).unwrap(); let _t = pallet_session::Pallet::::set_keys( RawOrigin::Signed(caller.clone()).into(), keys, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 48e8b651ebc46..7c444359209de 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -133,6 +133,7 @@ runtime-benchmarks = [ "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 26bf9731690bb..7944e1ff40414 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -183,6 +183,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-revive/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking-async-rc-client/runtime-benchmarks", "pallet-staking-async/runtime-benchmarks", "pallet-staking/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index c6bd870e78863..8f36b2e4875a7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -243,6 +243,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 49c6861c99bec..bfc46ffe66cbb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -252,6 +252,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 1f2606e953f86..6afa0188191ba 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -127,6 +127,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index 6d9de54ca9685..6320dd8ef4400 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -170,6 +170,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 4e366d0eacd0f..a40bebb5747c0 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -170,6 +170,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index d451018532c89..ade7dee71673c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -170,6 +170,7 @@ runtime-benchmarks = [ "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 9e0dd19a9aa3a..5dc76682c9092 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -172,6 +172,7 @@ runtime-benchmarks = [ "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 44b27445414cb..7d76b9c5a81e0 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -177,6 +177,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-revive/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index c4c43f2102639..31a7269148012 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -131,6 +131,7 @@ runtime-benchmarks = [ "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", "pallet-identity/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 5cf22bbd38c38..cddfb75d3e9f9 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -131,6 +131,7 @@ runtime-benchmarks = [ "pallet-broker/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index f99aa2d1b1936..4aa076faac431 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -76,6 +76,7 @@ where let proof: Vec = vec![]; whitelist_account!(controller); + pallet_session::Pallet::::ensure_can_pay_key_deposit(&controller).unwrap(); pallet_session::Pallet::::set_keys(RawOrigin::Signed(controller).into(), keys, proof) .expect("session::set_keys should work"); } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 96c613014e94a..be65accb31cee 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -244,6 +244,7 @@ runtime-benchmarks = [ "pallet-recovery/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index b9119d5f9c57d..4c4a79500f250 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -132,6 +132,7 @@ runtime-benchmarks = [ "pallet-grandpa/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 30174bf794908..b44bdf62c3bb1 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -267,6 +267,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking-async-ah-client/runtime-benchmarks", "pallet-staking-async-rc-client/runtime-benchmarks", "pallet-staking/runtime-benchmarks", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index c3107ab3db8a3..b65cb71d6899e 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -509,6 +509,7 @@ impl pallet_authorship::Config for Runtime { parameter_types! { pub const Period: BlockNumber = 10 * MINUTES; pub const Offset: BlockNumber = 0; + pub const KeyDeposit: Balance = deposit(1, 5 * 32 + 33); } impl_opaque_keys! { @@ -534,7 +535,7 @@ impl pallet_session::Config for Runtime { type DisablingStrategy = pallet_session::disabling::UpToLimitWithReEnablingDisablingStrategy; type WeightInfo = weights::pallet_session::WeightInfo; type Currency = Balances; - type KeyDeposit = (); + type KeyDeposit = KeyDeposit; } impl pallet_session::historical::Config for Runtime { diff --git a/polkadot/runtime/westend/src/weights/pallet_session.rs b/polkadot/runtime/westend/src/weights/pallet_session.rs index 813c6e3a66711..9f93de3cb9e66 100644 --- a/polkadot/runtime/westend/src/weights/pallet_session.rs +++ b/polkadot/runtime/westend/src/weights/pallet_session.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `3a2e9ae8a8f5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `276823fd1fd5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -51,36 +51,36 @@ use core::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Session::NextKeys` (r:1 w:1) /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Session::KeyOwner` (r:6 w:6) /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(139), added: 2614, mode: `MaxEncodedLen`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1899` - // Estimated: `17739` - // Minimum execution time: 71_274_000 picoseconds. - Weight::from_parts(73_693_000, 0) - .saturating_add(Weight::from_parts(0, 17739)) + // Measured: `1154` + // Estimated: `16994` + // Minimum execution time: 98_517_000 picoseconds. + Weight::from_parts(101_461_000, 0) + .saturating_add(Weight::from_parts(0, 16994)) .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Session::NextKeys` (r:1 w:1) /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(139), added: 2614, mode: `MaxEncodedLen`) /// Storage: `Session::KeyOwner` (r:0 w:6) /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1814` - // Estimated: `5279` - // Minimum execution time: 52_441_000 picoseconds. - Weight::from_parts(55_437_000, 0) - .saturating_add(Weight::from_parts(0, 5279)) + // Measured: `1141` + // Estimated: `4606` + // Minimum execution time: 71_897_000 picoseconds. + Weight::from_parts(74_310_000, 0) + .saturating_add(Weight::from_parts(0, 4606)) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(8)) } } diff --git a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs index d75724d1ae0f5..866a160598acf 100644 --- a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs +++ b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `polkadot_runtime_parachains::disputes::slashing` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `3a2e9ae8a8f5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `276823fd1fd5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -61,12 +61,16 @@ impl polkadot_runtime_parachains::disputes::slashing::W /// Proof: `Offences::ConcurrentReportsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Offences::Reports` (r:1 w:1) /// Proof: `Offences::Reports` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `StakingAhClient::Mode` (r:1 w:0) + /// Proof: `StakingAhClient::Mode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashRewardFraction` (r:1 w:0) + /// Proof: `Staking::SlashRewardFraction` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ActiveEra` (r:1 w:0) /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) /// Storage: `Staking::Invulnerables` (r:1 w:0) - /// Proof: `Staking::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Proof: `Staking::Invulnerables` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasStakersOverview` (r:1 w:0) /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Session::DisabledValidators` (r:1 w:1) @@ -75,22 +79,24 @@ impl polkadot_runtime_parachains::disputes::slashing::W /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Staking::ValidatorSlashInEra` (r:1 w:1) /// Proof: `Staking::ValidatorSlashInEra` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::OffenceQueue` (r:1 w:1) - /// Proof: `Staking::OffenceQueue` (`max_values`: None, `max_size`: Some(101), added: 2576, mode: `MaxEncodedLen`) - /// Storage: `Staking::OffenceQueueEras` (r:1 w:1) - /// Proof: `Staking::OffenceQueueEras` (`max_values`: Some(1), `max_size`: Some(9), added: 504, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:1 w:1) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::SpanSlash` (r:1 w:1) + /// Proof: `Staking::SpanSlash` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`) + /// Storage: `Staking::UnappliedSlashes` (r:1 w:1) + /// Proof: `Staking::UnappliedSlashes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `n` is `[4, 300]`. fn report_dispute_lost_unsigned(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2024 + n * (33 ±0)` - // Estimated: `5386 + n * (34 ±0)` - // Minimum execution time: 88_786_000 picoseconds. - Weight::from_parts(127_346_367, 0) - .saturating_add(Weight::from_parts(0, 5386)) - // Standard Error: 3_530 - .saturating_add(Weight::from_parts(144_389, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `2145 + n * (33 ±0)` + // Estimated: `5588 + n * (34 ±0)` + // Minimum execution time: 106_507_000 picoseconds. + Weight::from_parts(151_695_565, 0) + .saturating_add(Weight::from_parts(0, 5588)) + // Standard Error: 4_446 + .saturating_add(Weight::from_parts(202_889, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(17)) + .saturating_add(T::DbWeight::get().writes(8)) .saturating_add(Weight::from_parts(0, 34).saturating_mul(n.into())) } } diff --git a/prdoc/pr_9504.prdoc b/prdoc/pr_9504.prdoc new file mode 100644 index 0000000000000..0e4eff770f916 --- /dev/null +++ b/prdoc/pr_9504.prdoc @@ -0,0 +1,62 @@ +title: Fix `pallet_session` benchmarks +doc: +- audience: Runtime Dev + description: |- + Fixes the benchmarking code of `pallet_session` such that it works with any `KeyDeposit`. +crates: +- name: westend-runtime + bump: minor +- name: pallet-session-benchmarking + bump: patch +- name: pallet-session + bump: patch +- name: polkadot-sdk + bump: patch +- name: polkadot-runtime-parachains + bump: patch +- name: pallet-babe + bump: patch +- name: pallet-staking + bump: patch +- name: pallet-grandpa + bump: patch +- name: polkadot-runtime-common + bump: patch +- name: pallet-beefy-mmr + bump: patch +- name: pallet-offences-benchmarking + bump: patch +- name: pallet-im-online + bump: patch +- name: pallet-staking-async-ah-client + bump: patch +- name: rococo-runtime + bump: patch +- name: pallet-collator-selection + bump: patch +- name: cumulus-pallet-session-benchmarking + bump: patch +- name: pallet-root-offences + bump: patch +- name: snowbridge-runtime-test-common + bump: patch +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch +- name: collectives-westend-runtime + bump: patch +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch +- name: people-rococo-runtime + bump: patch +- name: people-westend-runtime + bump: patch +- name: penpal-runtime + bump: patch diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 0fa83b391145c..ca7d79e4d4ebf 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -73,6 +73,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 6adf5bcd871f5..c87b723f7cf7b 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -75,6 +75,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", ] diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 8fe651de43d99..6215d29c5e749 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -75,6 +75,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index f00260feac914..d459646e9ee76 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -56,6 +56,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", ] diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 27fc5101eff63..fe1b233f66f45 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -73,6 +73,7 @@ runtime-benchmarks = [ "pallet-grandpa/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-offences/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 91c30061957d4..31c99800ae3ed 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -112,6 +112,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' ::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) .unwrap(); let proof: Vec = vec![0, 1, 2, 3]; + Session::::ensure_can_pay_key_deposit(&stash)?; Session::::set_keys(RawOrigin::Signed(stash.clone()).into(), keys, proof)?; let mut individual_exposures = vec![]; diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index 5a28ae7b9697e..d5025d1214172 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -59,6 +59,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 18905d6a56a2d..d754371c38f1f 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -58,3 +58,11 @@ try-runtime = [ "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", ] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", +] diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index 1fa7e76bc29b7..384c452364d21 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -56,6 +56,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/session/benchmarking/src/inner.rs b/substrate/frame/session/benchmarking/src/inner.rs index f3707763f3509..bcff238d4ea0a 100644 --- a/substrate/frame/session/benchmarking/src/inner.rs +++ b/substrate/frame/session/benchmarking/src/inner.rs @@ -23,7 +23,10 @@ use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; use codec::Decode; use frame_benchmarking::v2::*; -use frame_support::traits::{Get, KeyOwnerProofSystem, OnInitialize}; +use frame_support::{ + assert_ok, + traits::{Get, KeyOwnerProofSystem, OnInitialize}, +}; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; use pallet_staking::{ @@ -66,6 +69,7 @@ mod benchmarks { // Whitelist controller account from further DB operations. let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); + assert_ok!(Session::::ensure_can_pay_key_deposit(&v_controller)); #[extrinsic_call] _(RawOrigin::Signed(v_controller), keys, proof); @@ -86,6 +90,7 @@ mod benchmarks { let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0, 1, 2, 3]; + assert_ok!(Session::::ensure_can_pay_key_deposit(&v_controller)); Session::::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?; // Whitelist controller account from further DB operations. let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 288bf56ad25ee..5910772e6d0fa 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -107,7 +107,9 @@ impl pallet_session::Config for Test { type DisablingStrategy = (); type WeightInfo = (); type Currency = Balances; - type KeyDeposit = (); + // Note: setting to a large amount to ensure bench setup can handle increasing the balance of + // the validator before setting session keys; see `ensure_can_pay_key_deposit`. + type KeyDeposit = ConstU64<2000000000>; } pallet_staking_reward_curve::build! { const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index bfa7540132293..ffafbd540d18f 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -129,7 +129,7 @@ use frame_support::{ dispatch::DispatchResult, ensure, traits::{ - fungible::{hold::Mutate as HoldMutate, Inspect}, + fungible::{hold::Mutate as HoldMutate, Inspect, Mutate}, Defensive, EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, ValidatorRegistration, ValidatorSet, }, @@ -447,7 +447,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The currency type for placing holds when setting keys. - type Currency: Inspect + type Currency: Mutate + HoldMutate>; /// The amount to be held when setting keys. @@ -668,6 +668,25 @@ pub mod pallet { Ok(()) } } + + #[cfg(feature = "runtime-benchmarks")] + impl Pallet { + /// Mint enough funds into `who`, such that they can pay the session key setting deposit. + /// + /// Meant to be used if any pallet's benchmarking code wishes to set session keys, and wants + /// to make sure it will succeed. + pub fn ensure_can_pay_key_deposit(who: &T::AccountId) -> Result<(), DispatchError> { + use frame_support::traits::tokens::{Fortitude, Preservation}; + let deposit = T::KeyDeposit::get(); + let has = T::Currency::reducible_balance(who, Preservation::Protect, Fortitude::Force); + if let Some(deficit) = deposit.checked_sub(&has) { + T::Currency::mint_into(who, deficit.max(T::Currency::minimum_balance())) + .map(|_inc| ()) + } else { + Ok(()) + } + } + } } impl Pallet { diff --git a/substrate/frame/staking-async/ah-client/Cargo.toml b/substrate/frame/staking-async/ah-client/Cargo.toml index 8a85f25375568..64edacc471349 100644 --- a/substrate/frame/staking-async/ah-client/Cargo.toml +++ b/substrate/frame/staking-async/ah-client/Cargo.toml @@ -47,6 +47,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking-async-rc-client/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", diff --git a/substrate/frame/staking-async/runtimes/parachain/Cargo.toml b/substrate/frame/staking-async/runtimes/parachain/Cargo.toml index 59d3a3a96fee7..183424a6b11e9 100644 --- a/substrate/frame/staking-async/runtimes/parachain/Cargo.toml +++ b/substrate/frame/staking-async/runtimes/parachain/Cargo.toml @@ -182,6 +182,7 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking-async-rc-client/runtime-benchmarks", "pallet-staking-async/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", diff --git a/substrate/frame/staking-async/runtimes/rc/Cargo.toml b/substrate/frame/staking-async/runtimes/rc/Cargo.toml index 5f9987431b3c6..273ac3f1f8799 100644 --- a/substrate/frame/staking-async/runtimes/rc/Cargo.toml +++ b/substrate/frame/staking-async/runtimes/rc/Cargo.toml @@ -257,6 +257,7 @@ runtime-benchmarks = [ "pallet-root-offences/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-staking-async-ah-client/runtime-benchmarks", "pallet-staking-async-rc-client/runtime-benchmarks", "pallet-staking/runtime-benchmarks", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 0d2457799e941..c2e72e16211fc 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -78,6 +78,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-session/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", "sp-runtime/runtime-benchmarks", diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index c9660322b6501..54b021e719485 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -319,6 +319,7 @@ runtime-benchmarks = [ "pallet-salary?/runtime-benchmarks", "pallet-scheduler?/runtime-benchmarks", "pallet-session-benchmarking?/runtime-benchmarks", + "pallet-session?/runtime-benchmarks", "pallet-skip-feeless-payment?/runtime-benchmarks", "pallet-society?/runtime-benchmarks", "pallet-staking-async-ah-client?/runtime-benchmarks", From 62e8f907c832545fe5090c49cf20160dabb27014 Mon Sep 17 00:00:00 2001 From: Raymond Cheung <178801527+raymondkfcheung@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:35:49 +0100 Subject: [PATCH 04/16] Enable `TopicIdTracker` to support multiple flows (#9316) This PR enables `TopicIdTracker` to support multiple flows. Continues on #9313 Closes #8676 to fix #8326 --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Andrii --- .../emulated/common/src/xcm_helpers.rs | 29 +++- .../src/tests/asset_transfers.rs | 26 ++-- polkadot/xcm/xcm-simulator/src/lib.rs | 142 +++++++++++++++++- prdoc/pr_9316.prdoc | 9 ++ 4 files changed, 180 insertions(+), 26 deletions(-) create mode 100644 prdoc/pr_9316.prdoc diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index a990e70434b1e..7a355337f11d1 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -92,19 +92,34 @@ pub fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { amount } +fn to_mq_processed_id(event: C::RuntimeEvent) -> Option +where + ::Runtime: pallet_message_queue::Config, + C::RuntimeEvent: TryInto::Runtime>>, +{ + if let Ok(pallet_message_queue::Event::Processed { id, .. }) = event.try_into() { + Some(id) + } else { + None + } +} + +/// Helper method to find all `Event::Processed` IDs from the chain's events. +pub fn find_all_mq_processed_ids() -> Vec +where + ::Runtime: pallet_message_queue::Config, + C::RuntimeEvent: TryInto::Runtime>>, +{ + C::events().into_iter().filter_map(to_mq_processed_id::).collect() +} + /// Helper method to find the ID of the first `Event::Processed` event in the chain's events. pub fn find_mq_processed_id() -> Option where ::Runtime: pallet_message_queue::Config, C::RuntimeEvent: TryInto::Runtime>>, { - C::events().into_iter().find_map(|event| { - if let Ok(pallet_message_queue::Event::Processed { id, .. }) = event.try_into() { - Some(id) - } else { - None - } - }) + C::events().into_iter().find_map(to_mq_processed_id::) } /// Helper method to find the message ID of the first `Event::Sent` event in the chain's events. diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 6bd130110eb7d..fa641e13c09fa 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -16,7 +16,7 @@ use crate::tests::{snowbridge_common::snowbridge_sovereign, *}; use emulated_integration_tests_common::{ macros::Dmp, - xcm_helpers::{find_mq_processed_id, find_xcm_sent_message_id}, + xcm_helpers::{find_all_mq_processed_ids, find_mq_processed_id, find_xcm_sent_message_id}, xcm_simulator::helpers::TopicIdTracker, }; use xcm::latest::AssetTransferFilter; @@ -1145,7 +1145,7 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc ); let msg_sent_id = - find_xcm_sent_message_id::().expect("Missing Sent Event"); + find_xcm_sent_message_id::().expect("Missing Sent Event on PenpalB"); topic_id_tracker.insert("PenpalB", msg_sent_id.into()); result @@ -1171,9 +1171,9 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc ) => {}, ] ); - let mq_prc_id = - find_mq_processed_id::().expect("Missing Processed Event"); - topic_id_tracker.insert("AssetHubWestend", mq_prc_id); + let mq_prc_ids = find_all_mq_processed_ids::(); + assert!(!mq_prc_ids.is_empty(), "Missing Processed Event on AssetHubWestend"); + topic_id_tracker.insert_all("AssetHubWestend", &mq_prc_ids); }); }); } @@ -1200,10 +1200,11 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc ) => {}, ] ); - let mq_prc_id = find_mq_processed_id::().expect("Missing Processed Event"); - topic_id_tracker.insert("AssetHubRococo", mq_prc_id); + let mq_prc_ids = find_all_mq_processed_ids::(); + assert!(!mq_prc_ids.is_empty(), "Missing Processed Event on AssetHubRococo"); + topic_id_tracker.insert_all("AssetHubRococo", &mq_prc_ids); }); - topic_id_tracker.assert_unique(); + topic_id_tracker.assert_only_id_seen_on_all_chains("PenpalB"); let sender_rocs_after = PenpalB::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -1482,8 +1483,9 @@ fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() { let wnd = Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]); AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - let mq_prc_id = find_mq_processed_id::().expect("Missing Processed Event"); - topic_id_tracker.insert_and_assert_unique("AssetHubRococo", mq_prc_id); + let mq_prc_ids = find_all_mq_processed_ids::(); + assert!(!mq_prc_ids.is_empty(), "Missing Processed Event on AssetHubRococo"); + topic_id_tracker.insert_all("AssetHubRococo", &mq_prc_ids); assert_expected_events!( AssetHubRococo, vec![ @@ -1500,8 +1502,8 @@ fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() { ); }); - // assert unique topic across all chains - topic_id_tracker.assert_unique(); + // assert that the only topic ID on 'PenpalB' exists on all chains + topic_id_tracker.assert_only_id_seen_on_all_chains("PenpalB"); // account balances after let sender_wnds_after = PenpalB::execute_with(|| { diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs index d494c64daacec..160240a6e12d9 100644 --- a/polkadot/xcm/xcm-simulator/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/src/lib.rs @@ -467,10 +467,51 @@ pub mod helpers { } } - /// A test utility for tracking XCM topic IDs - #[derive(Clone)] + /// A test utility for tracking XCM topic IDs. + /// + /// # Examples + /// + /// ``` + /// use sp_runtime::testing::H256; + /// use xcm_simulator::helpers::TopicIdTracker; + /// + /// // Dummy topic IDs + /// let topic_id = H256::repeat_byte(0x42); + /// + /// // Create a new tracker + /// let mut tracker = TopicIdTracker::new(); + /// + /// // Insert the same topic ID for three chains + /// tracker.insert("ChainA", topic_id); + /// tracker.insert_all("ChainB", &[topic_id]); + /// tracker.insert_and_assert_unique("ChainC", topic_id); + /// + /// // Assert the topic ID exists everywhere + /// tracker.assert_contains("ChainA", &topic_id); + /// tracker.assert_id_seen_on_all_chains(&topic_id); + /// tracker.assert_only_id_seen_on_all_chains("ChainB"); + /// tracker.assert_unique(); + /// + /// // You can also test that inserting inconsistent topic IDs fails: + /// let another_id = H256::repeat_byte(0x43); + /// let result = std::panic::catch_unwind(|| { + /// let mut tracker = TopicIdTracker::new(); + /// tracker.insert("ChainA", topic_id); + /// tracker.insert_and_assert_unique("ChainB", another_id); + /// }); + /// assert!(result.is_err()); + /// + /// let result = std::panic::catch_unwind(|| { + /// let mut tracker = TopicIdTracker::new(); + /// tracker.insert("ChainA", topic_id); + /// tracker.insert("ChainB", another_id); + /// tracker.assert_unique(); + /// }); + /// assert!(result.is_err()); + /// ``` + #[derive(Clone, Debug)] pub struct TopicIdTracker { - ids: HashMap, + ids: HashMap>, } impl TopicIdTracker { /// Initialises a new, empty topic ID tracker. @@ -478,9 +519,53 @@ pub mod helpers { TopicIdTracker { ids: HashMap::new() } } + /// Asserts that the given topic ID has been recorded for the specified chain. + pub fn assert_contains(&self, chain: &str, id: &H256) { + let ids = self + .ids + .get(chain) + .expect(&format!("No topic IDs recorded for chain '{}'", chain)); + + assert!( + ids.contains(id), + "Expected topic ID {:?} not found for chain '{}'. Found topic IDs: {:?}", + id, + chain, + ids + ); + } + + /// Asserts that the given topic ID has been recorded on all chains. + pub fn assert_id_seen_on_all_chains(&self, id: &H256) { + self.ids.keys().for_each(|chain| { + self.assert_contains(chain, id); + }); + } + + /// Asserts that exactly one topic ID is recorded on the given chain, and that the same ID + /// is present on all other chains. + pub fn assert_only_id_seen_on_all_chains(&self, chain: &str) { + let ids = self + .ids + .get(chain) + .expect(&format!("No topic IDs recorded for chain '{}'", chain)); + + assert_eq!( + ids.len(), + 1, + "Expected exactly one topic ID for chain '{}', but found {}: {:?}", + chain, + ids.len(), + ids + ); + + let id = *ids.iter().next().unwrap(); + self.assert_id_seen_on_all_chains(&id); + } + /// Asserts that exactly one unique topic ID is present across all captured entries. pub fn assert_unique(&self) { - let unique_ids: HashSet<_> = self.ids.values().collect(); + let unique_ids: HashSet<_> = self.ids.values().flatten().collect(); assert_eq!( unique_ids.len(), 1, @@ -492,14 +577,28 @@ pub mod helpers { /// Inserts a topic ID with the given chain name in the captor. pub fn insert(&mut self, chain: &str, id: H256) { - self.ids.insert(chain.to_string(), id); + self.ids.entry(chain.to_string()).or_default().insert(id); + } + + /// Inserts all topic IDs associated with the given chain name. + pub fn insert_all(&mut self, chain: &str, ids: &[H256]) { + ids.iter().for_each(|&id| self.insert(chain, id)); } /// Inserts a topic ID for a given chain and then asserts global uniqueness. pub fn insert_and_assert_unique(&mut self, chain: &str, id: H256) { - if let Some(existing_id) = self.ids.get(chain) { + if let Some(existing_ids) = self.ids.get(chain) { assert_eq!( - id, *existing_id, + existing_ids.len(), + 1, + "Expected exactly one topic ID for chain '{}', but found: {:?}", + chain, + existing_ids + ); + let existing_id = + *existing_ids.iter().next().expect(&format!("Topic ID for chain '{}'", chain)); + assert_eq!( + id, existing_id, "Topic ID mismatch for chain '{}': expected {:?}, got {:?}", id, existing_id, chain ); @@ -509,4 +608,33 @@ pub mod helpers { self.assert_unique(); } } + + #[cfg(test)] + mod tests { + use super::*; + use sp_runtime::testing::H256; + + #[test] + #[should_panic(expected = "Expected exactly one topic ID")] + fn test_assert_unique_fails_with_multiple_ids() { + let mut tracker = TopicIdTracker::new(); + let id1 = H256::repeat_byte(0x42); + let id2 = H256::repeat_byte(0x43); + + tracker.insert("ChainA", id1); + tracker.insert("ChainB", id2); + tracker.assert_unique(); + } + + #[test] + #[should_panic(expected = "Topic ID mismatch")] + fn test_insert_and_assert_unique_mismatch() { + let mut tracker = TopicIdTracker::new(); + let id1 = H256::repeat_byte(0x42); + let id2 = H256::repeat_byte(0x43); + + tracker.insert_and_assert_unique("ChainA", id1); + tracker.insert_and_assert_unique("ChainA", id2); + } + } } diff --git a/prdoc/pr_9316.prdoc b/prdoc/pr_9316.prdoc new file mode 100644 index 0000000000000..dcd1712fa1e84 --- /dev/null +++ b/prdoc/pr_9316.prdoc @@ -0,0 +1,9 @@ +title: Enable `TopicIdTracker` to support multiple flows +doc: +- audience: Runtime Dev + description: This PR enables `TopicIdTracker` to support multiple flows. +crates: +- name: emulated-integration-tests-common + bump: minor +- name: xcm-simulator + bump: minor From b6bf2b43daa35def3e56eb5f958a0fc3c67882c3 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Wed, 20 Aug 2025 10:54:05 +0200 Subject: [PATCH 05/16] [CI/CD] Fix build binary flow (#9526) This PR fixes build-binary flow, that is used to build a binary for the testing purposes from any branch. The issue was that there were too many input args for the build script. --- .github/workflows/release-build-binary.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-build-binary.yml b/.github/workflows/release-build-binary.yml index a5adab421a8a4..1fab39a7ef9fa 100644 --- a/.github/workflows/release-build-binary.yml +++ b/.github/workflows/release-build-binary.yml @@ -66,11 +66,12 @@ jobs: PROFILE=${{ inputs.profile }} if [ "${{ inputs.binary }}" = "polkadot" ]; then for binary in polkadot polkadot-prepare-worker polkadot-execute-worker; do - echo "Building $binary..." - ./.github/scripts/release/build-linux-release.sh $binary ${{ inputs.package }} "${PROFILE}" ${{ inputs.features }} + echo "Building $binary with profile $PROFILE and features ${{ inputs.features }}" + ./.github/scripts/release/build-linux-release.sh $binary ${{ inputs.package }} ${{ inputs.features }} done else - ./.github/scripts/release/build-linux-release.sh ${{ inputs.binary }} ${{ inputs.package }} "${PROFILE}" ${{ inputs.features }} + echo "Building ${{ inputs.binary }} with profile $PROFILE and features ${{ inputs.features }}" + ./.github/scripts/release/build-linux-release.sh ${{ inputs.binary }} ${{ inputs.package }} ${{ inputs.features }} fi - name: Upload ${{ inputs.binary }} artifacts From 62d218caefba6b38b92cfe1677869d2d379cb30c Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:47:46 +0300 Subject: [PATCH 06/16] fix: add missing crates bumps and upgrade parity-publish (#9488) # Description Adds a few crate bumps associated to PRs which missed to bump them, and updates parity-publish version across the board to 0.10.6 (to support rustc 1.88). Additionally, makes it so that parity-publish-check-compile runs first on all unreleased prdocs to bump associated crates, and only after moving those to an `unreleased` directory, runs on the current PR's prdoc. This is so that we first create a "local release" based on the unreleased prdocs, and then we follow with a "patch" release based on the previous local release, considering only the prdoc pushed with the current PR. If the workflow fails at the end it means current PR missed certain bumps. If we don't do the plan/apply twice we risk to miss bumps due to all prdocs being considered (current PR's prdoc + unreleased ones) when running parity-publish plan/apply, which might result in a set of crate bumps which are sufficient, but once some unreleased prdocs will be moved to a stable prodoc directory, because they will be part of a stable release, then the ones left will not be enough from a bump perspective (e.g. like it happened in #9320). That's why it is important to check every PR that adds a prdoc whether it is self-sufficient from a crates bumping perspective. If no prdoc is provided, the parity-publish does not need to be taken into consideration, but it should also pass nonetheless. ## Integration N/A ## Review Notes There seems to a be a corner case parity-publish can not easily catch. All bumps below are a manifestation of it. More details below: * #8714 - a major bump is necessary for `sp-wasm-interface` - context here: https://github.com/paritytech/polkadot-sdk/pull/8714#discussion_r2273355186 * `sp-keystore` was bumped during 2506 in #6010 , and the relevant prdoc got moved to stable2506 dir in #9320. This moved prdoc coexisted alongside other unreleased prdocs, and covered a needed patch bump for `sp-keystore`, that is not easily visible, and also required for crates publishing IIUC: 1. `sp-io` is major bumped because its direct dependency, `sp-state-machine`, was major bumped. 2. `sp-io` has a direct dependency on `sp-core` (minor bumped), and `sp-keystore` (not touched, not bumped by now) 3. `sp-io` fails to compile because it pulls same types from different `sp-core` versions (it implements `Keystore` trait from `sp-keystore` with methods signatures referencing types from `sp-core 38.0.0` by using the `sp-core 0.38.1` - unreleased yet - types, which confuses rustc). * `sp-rpc` needs a bump too due to pulling `sp-core 38.0.0`, like `sp-keystore`, and it is an indirect dependency of `polkadot-cli`, which has also a direct dependency on unreleased `sp-core 38.1.0`, so again, if we don't bump `sp-rpc` (historically it has been bumped only with major, but I think we can go with patch on this one), `polkadot-cli` can't compile. * `sc-storage-monitor` is in a similar situation as `sp-rpc`/`sp-keystore` - `polkadot-cli` depends on `sc-storage-monitor` (which is not bumped, and has a dependency on `sp-core 38.0.0`), but it also depends on `sp-core 38.1.0`. And yet again, something is used in `polkadot-cli` from the two different `sp-core` versions, which confuses rustc. --------- Signed-off-by: Iulian Barbu Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .github/workflows/check-semver.yml | 4 +-- .github/workflows/publish-check-compile.yml | 31 +++++++++++++++++++-- .github/workflows/publish-check-crates.yml | 2 +- prdoc/pr_9488.prdoc | 14 ++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 prdoc/pr_9488.prdoc diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml index 08359b979712c..73509a94462de 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - TOOLCHAIN: nightly-2025-01-26 + TOOLCHAIN: nightly-2025-05-09 jobs: isdraft: @@ -78,7 +78,7 @@ jobs: - name: Install parity-publish # Set the target dir to cache the build. - run: CARGO_TARGET_DIR=./target/ cargo install parity-publish@0.10.5 --locked -q + run: CARGO_TARGET_DIR=./target/ cargo install parity-publish@0.10.6 --locked -q - name: Get original PR number shell: bash diff --git a/.github/workflows/publish-check-compile.yml b/.github/workflows/publish-check-compile.yml index d1b537ba49058..a7c1d3faa4cc0 100644 --- a/.github/workflows/publish-check-compile.yml +++ b/.github/workflows/publish-check-compile.yml @@ -38,9 +38,36 @@ jobs: - name: install parity-publish run: | - cargo install parity-publish@0.10.4 --locked -q + cargo install parity-publish@0.10.6 --locked -q - - name: parity-publish update plan + - name: set current PR's prdoc name in a variable + env: + GITHUB_PR_NUM: ${{ github.event.pull_request.number }} + run: | + echo "CURRENT_PRDOC=pr_${GITHUB_PR_NUM}.prdoc" >> $GITHUB_ENV + + - name: parity-publish update plan w/o current prdoc + run: | + mv prdoc/$CURRENT_PRDOC . + parity-publish --color always plan --skip-check --prdoc prdoc/ + + # The code base is not in master's state (due to commits brought by the + # current PR), but we're interested in all master's prdocs to be applied + # as if master is a stable branch, and in next steps we're following up with + # a patch release of all crates based on some newly added prdocs + # (meaning only the current prdoc). + - name: parity-publish apply plan on the code state prior to current prdoc + run: parity-publish --color always apply --registry + + - name: move all prdocs except current one to unstable dir + run: | + mkdir prdoc/unstable + mv prdoc/pr_*.prdoc prdoc/unstable + if [ -f $CURRENT_PRDOC ]; then + mv $CURRENT_PRDOC prdoc + fi + + - name: parity-publish update plan just for PR's prdoc run: parity-publish --color always plan --skip-check --prdoc prdoc/ - name: parity-publish apply plan diff --git a/.github/workflows/publish-check-crates.yml b/.github/workflows/publish-check-crates.yml index 7aef518e90d10..3ffd0515f22fe 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -27,7 +27,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.10.4 --locked -q + run: cargo install parity-publish@0.10.6 --locked -q - name: parity-publish check run: parity-publish --color always check --allow-unpublished diff --git a/prdoc/pr_9488.prdoc b/prdoc/pr_9488.prdoc new file mode 100644 index 0000000000000..6f0fb26e3078c --- /dev/null +++ b/prdoc/pr_9488.prdoc @@ -0,0 +1,14 @@ +title: 'prdoc: add missing crates bumps' +doc: +- audience: Node Dev + description: + Adds a few crate bumps associated to PRs which missed to bump them due to a corner case missed by the release tooling. +crates: + - name: sp-wasm-interface + bump: major + - name: sp-rpc + bump: patch + - name: sc-storage-monitor + bump: patch + - name: sp-keystore + bump: patch From be4d8d0dcec1032dba8212a881f3cfdc670034b5 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 20 Aug 2025 11:20:41 -0500 Subject: [PATCH 07/16] Added `subkey` to CI release process (#9466) - Added 2 jobs to `Release - Build node release candidate` CI workflow for linux/mac subkey binaries - Added 2 jobs to `RC Build` CI workflow to upload linux/mac `subkey` artifacts to S3 - updated `release_lib.sh` to reflect new S3 artifacts CLOSES: #9465 --------- Co-authored-by: EgorPopelyaev --- .github/scripts/release/release_lib.sh | 3 + .github/workflows/release-20_build-rc.yml | 31 +++++ ...mbined-rc-runtime-builds-release-draft.yml | 1 + .../workflows/release-reusable-rc-build.yml | 109 ++++++++---------- .../workflows/release-reusable-s3-upload.yml | 8 -- 5 files changed, 80 insertions(+), 72 deletions(-) diff --git a/.github/scripts/release/release_lib.sh b/.github/scripts/release/release_lib.sh index f4ac971824c48..c468599b364de 100644 --- a/.github/scripts/release/release_lib.sh +++ b/.github/scripts/release/release_lib.sh @@ -195,6 +195,9 @@ function get_s3_url_base() { eth-rpc) printf "releases.parity.io/eth-rpc" ;; + subkey) + printf "releases.parity.io/subkey" + ;; *) printf "UNSUPPORTED BINARY $name" exit 1 diff --git a/.github/workflows/release-20_build-rc.yml b/.github/workflows/release-20_build-rc.yml index 11d126a69be39..e11d0070bde76 100644 --- a/.github/workflows/release-20_build-rc.yml +++ b/.github/workflows/release-20_build-rc.yml @@ -15,6 +15,7 @@ on: - chain-spec-builder - substrate-node - eth-rpc + - subkey - all release_tag: @@ -163,6 +164,21 @@ jobs: attestations: write contents: read + build-subkey-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'subkey' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-build.yml" + with: + binary: '["subkey"]' + package: subkey + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: inherit + permissions: + id-token: write + attestations: write + contents: read + build-polkadot-macos-binary: needs: [validate-inputs] if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} @@ -268,3 +284,18 @@ jobs: id-token: write attestations: write contents: read + + build-subkey-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'subkey' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-build.yml" + with: + binary: '["subkey"]' + package: subkey + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: inherit + permissions: + id-token: write + attestations: write + contents: read diff --git a/.github/workflows/release-22_combined-rc-runtime-builds-release-draft.yml b/.github/workflows/release-22_combined-rc-runtime-builds-release-draft.yml index f8473be81ee14..ac5e4b0af8ab9 100644 --- a/.github/workflows/release-22_combined-rc-runtime-builds-release-draft.yml +++ b/.github/workflows/release-22_combined-rc-runtime-builds-release-draft.yml @@ -41,6 +41,7 @@ on: - chain-spec-builder - substrate-node - eth-rpc + - subkey - all release_tag: description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcY or polkadot-stableYYMM(-X) diff --git a/.github/workflows/release-reusable-rc-build.yml b/.github/workflows/release-reusable-rc-build.yml index 973796cbf39f2..77bc48104cc59 100644 --- a/.github/workflows/release-reusable-rc-build.yml +++ b/.github/workflows/release-reusable-rc-build.yml @@ -301,10 +301,7 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-polkadot-parachain-artifacts-to-s3: if: ${{ inputs.package == 'polkadot-parachain-bin' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -314,10 +311,7 @@ jobs: package: polkadot-parachain release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-polkadot-omni-node-artifacts-to-s3: if: ${{ inputs.package == 'polkadot-omni-node' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -327,10 +321,7 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-frame-omni-bencher-artifacts-to-s3: if: ${{ inputs.package == 'frame-omni-bencher' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -340,10 +331,7 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-chain-spec-builder-artifacts-to-s3: if: ${{ inputs.package == 'staging-chain-spec-builder' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -353,10 +341,7 @@ jobs: package: chain-spec-builder release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-substrate-node-artifacts-to-s3: if: ${{ inputs.package == 'staging-node-cli' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -366,10 +351,7 @@ jobs: package: substrate-node release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-eth-rpc-artifacts-to-s3: if: ${{ inputs.package == 'pallet-revive-eth-rpc' && inputs.target == 'x86_64-unknown-linux-gnu' }} @@ -379,10 +361,17 @@ jobs: package: eth-rpc release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit + + upload-subkey-artifacts-to-s3: + if: ${{ inputs.package == 'subkey' && inputs.target == 'x86_64-unknown-linux-gnu' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: subkey + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: inherit upload-polkadot-macos-artifacts-to-s3: if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} @@ -394,10 +383,7 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-polkadot-prepare-worker-macos-artifacts-to-s3: if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} @@ -407,10 +393,7 @@ jobs: package: polkadot-prepare-worker release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-polkadot-execute-worker-macos-artifacts-to-s3: if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} @@ -420,10 +403,10 @@ jobs: package: polkadot-execute-worker release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit + # AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + # AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + # AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} upload-polkadot-omni-node-macos-artifacts-to-s3: if: ${{ inputs.package == 'polkadot-omni-node' && inputs.target == 'aarch64-apple-darwin' }} @@ -433,10 +416,7 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-polkadot-parachain-macos-artifacts-to-s3: if: ${{ inputs.package == 'polkadot-parachain-bin' && inputs.target == 'aarch64-apple-darwin' }} @@ -446,10 +426,7 @@ jobs: package: polkadot-parachain release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-frame-omni-bencher-macos-artifacts-to-s3: if: ${{ inputs.package == 'frame-omni-bencher' && inputs.target == 'aarch64-apple-darwin' }} @@ -459,10 +436,10 @@ jobs: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit + # AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + # AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + # AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} upload-chain-spec-builder-macos-artifacts-to-s3: if: ${{ inputs.package == 'staging-chain-spec-builder' && inputs.target == 'aarch64-apple-darwin' }} @@ -472,10 +449,7 @@ jobs: package: chain-spec-builder release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit upload-substrate-node-macos-artifacts-to-s3: if: ${{ inputs.package == 'staging-node-cli' && inputs.target == 'aarch64-apple-darwin' }} @@ -485,10 +459,10 @@ jobs: package: substrate-node release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit + # AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + # AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + # AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} upload-eth-rpc-macos-artifacts-to-s3: if: ${{ inputs.package == 'pallet-revive-eth-rpc' && inputs.target == 'aarch64-apple-darwin' }} @@ -498,7 +472,14 @@ jobs: package: eth-rpc release_tag: ${{ inputs.release_tag }} target: ${{ inputs.target }} - secrets: - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + secrets: inherit + + upload-subkey-macos-artifacts-to-s3: + if: ${{ inputs.package == 'subkey' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: subkey + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: inherit diff --git a/.github/workflows/release-reusable-s3-upload.yml b/.github/workflows/release-reusable-s3-upload.yml index b4c7b5d77bb53..b4606ef23437a 100644 --- a/.github/workflows/release-reusable-s3-upload.yml +++ b/.github/workflows/release-reusable-s3-upload.yml @@ -18,14 +18,6 @@ on: required: true type: string - secrets: - AWS_DEFAULT_REGION: - required: true - AWS_RELEASE_ACCESS_KEY_ID: - required: true - AWS_RELEASE_SECRET_ACCESS_KEY: - required: true - jobs: upload-artifacts-to-s3: runs-on: ubuntu-latest From 96bec678157825d775678649c67cc656b3a377e7 Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:09:47 +0300 Subject: [PATCH 08/16] fix: publish-check-compile support no prdoc PRs (#9532) # Description `publish-check-compile` workflows fails if the PR has no prdoc. Add a few checks everytime we assume a prdoc exists. ## Integration N/A ## Review Notes N/A Signed-off-by: Iulian Barbu --- .github/workflows/publish-check-compile.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-check-compile.yml b/.github/workflows/publish-check-compile.yml index a7c1d3faa4cc0..f0b4ce27f626d 100644 --- a/.github/workflows/publish-check-compile.yml +++ b/.github/workflows/publish-check-compile.yml @@ -48,7 +48,9 @@ jobs: - name: parity-publish update plan w/o current prdoc run: | - mv prdoc/$CURRENT_PRDOC . + if [ -f prdoc/$CURRENT_PRDOC ]; then + mv prdoc/$CURRENT_PRDOC . + fi parity-publish --color always plan --skip-check --prdoc prdoc/ # The code base is not in master's state (due to commits brought by the @@ -61,17 +63,23 @@ jobs: - name: move all prdocs except current one to unstable dir run: | - mkdir prdoc/unstable - mv prdoc/pr_*.prdoc prdoc/unstable if [ -f $CURRENT_PRDOC ]; then + mkdir prdoc/unstable + mv prdoc/pr_*.prdoc prdoc/unstable mv $CURRENT_PRDOC prdoc fi - name: parity-publish update plan just for PR's prdoc - run: parity-publish --color always plan --skip-check --prdoc prdoc/ + run: | + if [ -f "prdoc/$CURRENT_PRDOC" ]; then + parity-publish --color always plan --skip-check --prdoc prdoc/ + fi - name: parity-publish apply plan - run: parity-publish --color always apply --registry + run: | + if [ -f "prdoc/$CURRENT_PRDOC" ]; then + parity-publish --color always apply --registry + fi - name: parity-publish check compile run: | From 96be5028fefe00caa7450691fdb0940519a8e379 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 21 Aug 2025 09:22:32 +0100 Subject: [PATCH 09/16] EPMB/Signed: Make invulnerables non-eject-able (#9511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to https://github.com/paritytech/polkadot-sdk/pull/8877 and audits: Make it such that invulnerable accounts cannot be ejected from the election signed queue altogether. --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Dónal Murray --- prdoc/pr_9511.prdoc | 11 + .../src/signed/mod.rs | 45 +++-- .../src/signed/tests.rs | 189 ++++++++++++------ .../runtimes/parachain/src/staking.rs | 6 +- .../frame/staking-async/src/pallet/impls.rs | 20 -- 5 files changed, 178 insertions(+), 93 deletions(-) create mode 100644 prdoc/pr_9511.prdoc diff --git a/prdoc/pr_9511.prdoc b/prdoc/pr_9511.prdoc new file mode 100644 index 0000000000000..35aa5f493e047 --- /dev/null +++ b/prdoc/pr_9511.prdoc @@ -0,0 +1,11 @@ +title: 'EPMB/Signed: Make invulnerables non-eject-able' +doc: +- audience: Runtime Dev + description: 'Follow-up to https://github.com/paritytech/polkadot-sdk/pull/8877 + and audits: Make it such that invulnerable accounts cannot be ejected from the + election signed queue altogether. ' +crates: +- name: pallet-election-provider-multi-block + bump: patch +- name: pallet-staking-async + bump: patch diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs index 9784cf75a5765..1aa0dadb2d452 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -452,13 +452,13 @@ pub mod pallet { ) -> Result { let mut sorted_scores = SortedScores::::get(round); - let discarded = if let Some(_) = sorted_scores.iter().position(|(x, _)| x == who) { + let did_eject = if let Some(_) = sorted_scores.iter().position(|(x, _)| x == who) { return Err(Error::::Duplicate.into()); } else { // must be new. debug_assert!(!SubmissionMetadataStorage::::contains_key(round, who)); - let pos = match sorted_scores + let insert_idx = match sorted_scores .binary_search_by_key(&metadata.claimed_score, |(_, y)| *y) { // an equal score exists, unlikely, but could very well happen. We just put them @@ -468,10 +468,23 @@ pub mod pallet { Err(pos) => pos, }; - let record = (who.clone(), metadata.claimed_score); - match sorted_scores.force_insert_keep_right(pos, record) { - Ok(None) => false, - Ok(Some((discarded, _score))) => { + let mut record = (who.clone(), metadata.claimed_score); + if sorted_scores.is_full() { + let remove_idx = sorted_scores + .iter() + .position(|(x, _)| !Pallet::::is_invulnerable(x)) + .ok_or(Error::::QueueFull)?; + if insert_idx > remove_idx { + // we have a better solution + sp_std::mem::swap(&mut sorted_scores[remove_idx], &mut record); + // slicing safety note: + // - `insert_idx` is at most `sorted_scores.len()`, obtained from + // `binary_search_by_key`, valid for the upper bound of slicing. + // - `remove_idx` is a valid index, less then `insert_idx`, obtained from + // `.iter().position()` + sorted_scores[remove_idx..insert_idx].rotate_left(1); + + let discarded = record.0; let maybe_metadata = SubmissionMetadataStorage::::take(round, &discarded).defensive(); // Note: safe to remove unbounded, as at most `Pages` pages are stored. @@ -486,24 +499,27 @@ pub mod pallet { Pallet::::settle_deposit( &discarded, metadata.deposit, - if Pallet::::is_invulnerable(&discarded) { - One::one() - } else { - T::EjectGraceRatio::get() - }, + T::EjectGraceRatio::get(), ); } Pallet::::deposit_event(Event::::Ejected(round, discarded)); true - }, - Err(_) => return Err(Error::::QueueFull.into()), + } else { + // we don't have a better solution + return Err(Error::::QueueFull.into()) + } + } else { + sorted_scores + .try_insert(insert_idx, record) + .expect("length checked above; qed"); + false } }; SortedScores::::insert(round, sorted_scores); SubmissionMetadataStorage::::insert(round, who, metadata); - Ok(discarded) + Ok(did_eject) } /// Submit a page of `solution` to the `page` index of `who`'s submission. @@ -1020,6 +1036,7 @@ impl Pallet { ); debug_assert_eq!(_res, Ok(slash)); Self::deposit_event(Event::::Slashed(current_round, loser.clone(), slash)); + Invulnerables::::mutate(|x| x.retain(|y| y != &loser)); // Try to start verification again if we still have submissions if let crate::types::Phase::SignedValidation(remaining_blocks) = diff --git a/substrate/frame/election-provider-multi-block/src/signed/tests.rs b/substrate/frame/election-provider-multi-block/src/signed/tests.rs index cbd64adf84c7d..085cec58935c4 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/tests.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/tests.rs @@ -29,6 +29,10 @@ use sp_npos_elections::ElectionScore; pub type T = Runtime; +fn score_from(x: u128) -> ElectionScore { + ElectionScore { minimal_stake: x, ..Default::default() } +} + mod calls { use super::*; use sp_runtime::{DispatchError, TokenError::FundsUnavailable}; @@ -213,13 +217,11 @@ mod calls { } #[test] - fn metadata_submission_sorted_based_on_stake() { + fn metadata_submission_sorted_based_on_score() { ExtBuilder::signed().build_and_execute(|| { roll_to_signed_open(); assert_full_snapshot(); - let score_from = |x| ElectionScore { minimal_stake: x, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(91), score_from(100))); assert_eq!(*Submissions::::leaderboard(0), vec![(91, score_from(100))]); assert_eq!(balances(91), (95, 5)); @@ -1259,6 +1261,8 @@ mod e2e { } mod invulnerables { + use frame_support::hypothetically; + use super::*; fn make_invulnerable(who: AccountId) { @@ -1395,73 +1399,102 @@ mod invulnerables { } #[test] - fn ejected_invulnerable_gets_deposit_back() { - ExtBuilder::signed().max_signed_submissions(2).build_and_execute(|| { + fn invulnerable_cannot_eject_first() { + ExtBuilder::signed().max_signed_submissions(3).build_and_execute(|| { roll_to_signed_open(); assert_full_snapshot(); make_invulnerable(99); - // by default, we pay back 20% of the discarded deposit back + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), score_from(100))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(98), score_from(150))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(97), score_from(200))); + assert_eq!( - ::EjectGraceRatio::get(), - Perbill::from_percent(20) + Submissions::::leaderboard(0), + vec![(99, score_from(100)), (98, score_from(150)), (97, score_from(200))] ); - // submit 99 as invulnerable - assert_ok!(SignedPallet::register( - RuntimeOrigin::signed(99), - ElectionScore { minimal_stake: 100, ..Default::default() } - )); - assert!(matches!( - Submissions::::metadata_of(0, 99).unwrap(), - SubmissionMetadata { deposit: 7, .. } - )); + // inserting someone who would eject 99 won't work. + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(96), score_from(100)), + Error::::QueueFull, + ); + // inserting someone who would eject 98 will work. + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(96), score_from(155))); + assert_eq!( + Submissions::::leaderboard(0), + vec![(99, score_from(100)), (96, score_from(155)), (97, score_from(200))] + ); + }) + } - // submit 98 as normal - assert_ok!(SignedPallet::register( - RuntimeOrigin::signed(98), - ElectionScore { minimal_stake: 101, ..Default::default() } - )); - assert!(matches!( - Submissions::::metadata_of(0, 98).unwrap(), - SubmissionMetadata { deposit: 5, .. } - )); - let _ = signed_events_since_last_call(); - assert_eq!(balances(99), (93, 7)); - assert_eq!(balances(98), (95, 5)); + #[test] + fn invulnerable_cannot_eject_middle() { + ExtBuilder::signed().max_signed_submissions(3).build_and_execute(|| { + roll_to_signed_open(); + assert_full_snapshot(); + make_invulnerable(99); - // submit 97 and 96 with higher scores, eject both of the previous ones - assert_ok!(SignedPallet::register( - RuntimeOrigin::signed(97), - ElectionScore { minimal_stake: 200, ..Default::default() } - )); - assert_ok!(SignedPallet::register( - RuntimeOrigin::signed(96), - ElectionScore { minimal_stake: 201, ..Default::default() } - )); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), score_from(150))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(98), score_from(100))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(97), score_from(200))); assert_eq!( - signed_events_since_last_call(), - vec![ - Event::Ejected(0, 99), - Event::Registered( - 0, - 97, - ElectionScore { minimal_stake: 200, sum_stake: 0, sum_stake_squared: 0 } - ), - Event::Ejected(0, 98), - Event::Registered( - 0, - 96, - ElectionScore { minimal_stake: 201, sum_stake: 0, sum_stake_squared: 0 } - ) - ] + Submissions::::leaderboard(0), + vec![(98, score_from(100)), (99, score_from(150)), (97, score_from(200))] ); - // 99 gets everything back - assert_eq!(balances(99), (100, 0)); - // 98 gets 20% x 5 = 1 back - assert_eq!(balances(98), (96, 0)); + // worse than all + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(96), score_from(50)), + Error::::QueueFull, + ); + + // better than our first item + hypothetically!({ + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(96), score_from(125))); + assert_eq!( + Submissions::::leaderboard(0), + vec![(96, score_from(125)), (99, score_from(150)), (97, score_from(200))] + ); + }); + + // better than inv + hypothetically!({ + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(96), score_from(175))); + assert_eq!( + Submissions::::leaderboard(0), + vec![(99, score_from(150)), (96, score_from(175)), (97, score_from(200))] + ); + }); + + // better than all + hypothetically!({ + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(96), score_from(225))); + assert_eq!( + Submissions::::leaderboard(0), + vec![(99, score_from(150)), (97, score_from(200)), (96, score_from(225))] + ); + }); + }) + } + + #[test] + fn all_invulnerables() { + ExtBuilder::signed().max_signed_submissions(3).build_and_execute(|| { + roll_to_signed_open(); + assert_full_snapshot(); + assert_ok!(SignedPallet::set_invulnerables(RuntimeOrigin::root(), vec![99, 98, 97])); + + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), score_from(150))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(98), score_from(100))); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(97), score_from(200))); + + // Nothing can touch our boys now. + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(96), score_from(1000)), + Error::::QueueFull, + ); }) } @@ -1559,6 +1592,48 @@ mod invulnerables { assert_eq!(new_deposit, 5); // Should not be fixed deposit anymore }); } + + #[test] + fn slashed_invulnerable_is_expelled() { + ExtBuilder::signed().build_and_execute(|| { + roll_to_signed_open(); + assert_full_snapshot(); + make_invulnerable(99); + assert!(Invulnerables::::get().contains(&99)); + + let invalid_score = score_from(777); + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), invalid_score)); + + roll_to_signed_validation_open(); + roll_next(); // one block so signed pallet will send start signal. + roll_to_full_verification(); + + // Check that rejection events were properly generated + assert_eq!( + verifier_events_since_last_call(), + vec![ + crate::verifier::Event::Verified(2, 0), // empty page + crate::verifier::Event::Verified(1, 0), // empty page + crate::verifier::Event::Verified(0, 0), // empty page + crate::verifier::Event::VerificationFailed(0, FeasibilityError::InvalidScore), + ] + ); + + // Check that expected events were emitted for the rejection + assert_eq!( + signed_events(), + vec![Event::Registered(0, 99, invalid_score), Event::Slashed(0, 99, 7)] /* slash + * amount + * is indeed + * the invulnerable + * deposit + * (7) ^^^^ */ + ); + + // Verify invulnerable is expelled + assert!(!Invulnerables::::get().contains(&99)); + }); + } } mod defensive_tests { diff --git a/substrate/frame/staking-async/runtimes/parachain/src/staking.rs b/substrate/frame/staking-async/runtimes/parachain/src/staking.rs index ab5c8f7fe4104..aa9da4dc520f4 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/staking.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/staking.rs @@ -81,8 +81,10 @@ parameter_types! { /// better. pub storage Pages: u32 = 4; - /// * Polkadot: 8 * 32 (256 blocks, 25.6m). Enough time to verify up to 8 solutions. - /// * Kusama: 4 * 16 (64 blocks, 6.4m). Enough time to verify up to 4 solutions. + /// * Polkadot: 16 * 32 (512 blocks, 51.2m). + /// * Kusama: 8 * 16 (12 blocks, 12.8m). + /// + /// (MaxSubmissions * Pages) for both, enough to verify all solutions. /// /// Reasoning: Less security needed in Kusama, to compensate for the shorter session duration. pub storage SignedValidationPhase: u32 = Pages::get() * 2; diff --git a/substrate/frame/staking-async/src/pallet/impls.rs b/substrate/frame/staking-async/src/pallet/impls.rs index 13bc247bcd6a0..8219aa1293f42 100644 --- a/substrate/frame/staking-async/src/pallet/impls.rs +++ b/substrate/frame/staking-async/src/pallet/impls.rs @@ -737,11 +737,6 @@ impl Pallet { .defensive_unwrap_or_default(); } Nominators::::insert(who, nominations); - - debug_assert_eq!( - Nominators::::count() + Validators::::count(), - T::VoterList::count() - ); } /// This function will remove a nominator from the `Nominators` storage map, @@ -761,11 +756,6 @@ impl Pallet { false }; - debug_assert_eq!( - Nominators::::count() + Validators::::count(), - T::VoterList::count() - ); - outcome } @@ -782,11 +772,6 @@ impl Pallet { let _ = T::VoterList::on_insert(who.clone(), Self::weight_of(who)); } Validators::::insert(who, prefs); - - debug_assert_eq!( - Nominators::::count() + Validators::::count(), - T::VoterList::count() - ); } /// This function will remove a validator from the `Validators` storage map. @@ -805,11 +790,6 @@ impl Pallet { false }; - debug_assert_eq!( - Nominators::::count() + Validators::::count(), - T::VoterList::count() - ); - outcome } From 147e8f923479643c8c672d1f6e791042fe35ede1 Mon Sep 17 00:00:00 2001 From: Raymond Cheung <178801527+raymondkfcheung@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:16:26 +0100 Subject: [PATCH 10/16] Replace `log` with `tracing` on `pallet-bridge-relayers` (#9381) This PR replaces `log` with `tracing` instrumentation on `pallet-bridge-relayers` by providing structured logging. Partially addresses #9211 --- Cargo.lock | 2 +- bridges/modules/relayers/Cargo.toml | 4 +- .../relayers/src/extension/grandpa_adapter.rs | 10 +- bridges/modules/relayers/src/extension/mod.rs | 59 ++++++------ .../src/extension/parachain_adapter.rs | 10 +- bridges/modules/relayers/src/lib.rs | 92 +++++++++---------- bridges/modules/relayers/src/migration.rs | 30 +++--- prdoc/pr_9381.prdoc | 8 ++ 8 files changed, 110 insertions(+), 105 deletions(-) create mode 100644 prdoc/pr_9381.prdoc diff --git a/Cargo.lock b/Cargo.lock index 9da0fa0359f25..1378f1767f018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11892,7 +11892,6 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log", "pallet-balances", "pallet-bridge-grandpa", "pallet-bridge-messages", @@ -11905,6 +11904,7 @@ dependencies = [ "sp-core 28.0.0", "sp-io", "sp-runtime", + "tracing", ] [[package]] diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 0a9b41a460229..1b27c2879e930 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -12,8 +12,8 @@ workspace = true [dependencies] codec = { workspace = true } -log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +tracing = { workspace = true } # Bridge dependencies bp-header-chain = { workspace = true } @@ -55,7 +55,6 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", - "log/std", "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", "pallet-bridge-parachains/std", @@ -66,6 +65,7 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", + "tracing/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/bridges/modules/relayers/src/extension/grandpa_adapter.rs b/bridges/modules/relayers/src/extension/grandpa_adapter.rs index 9e98c73f8da04..a8466fe22aca8 100644 --- a/bridges/modules/relayers/src/extension/grandpa_adapter.rs +++ b/bridges/modules/relayers/src/extension/grandpa_adapter.rs @@ -156,12 +156,12 @@ where finality_proof_info.block_number, ) { // we only refund relayer if all calls have updated chain state - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: relayer {:?} has submitted invalid GRANDPA chain finality proof", - C::IdProvider::STR, - call_info.messages_call_info().lane_id(), - relayer, + id_provider=%C::IdProvider::STR, + lane_id=?call_info.messages_call_info().lane_id(), + ?relayer, + "Relayer has submitted invalid GRANDPA chain finality proof" ); return false } diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 8d03a0db2e509..c953ab836e9c2 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -221,13 +221,13 @@ where // We don't refund anything if the transaction has failed. if let Err(e) = result { - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: relayer {:?} has submitted invalid messages transaction: {:?}", - Self::IDENTIFIER, - lane_id, - relayer, - e, + error=?e, + id_provider=%Self::IDENTIFIER, + ?lane_id, + ?relayer, + "Relayer has submitted invalid messages transaction", ); return slash_relayer_if_delivery_result } @@ -346,15 +346,14 @@ where priority::compute_priority_boost::(bundled_messages); let valid_transaction = ValidTransactionBuilder::default().priority(priority_boost); - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: has boosted priority of message delivery transaction \ - of relayer {:?}: {} messages -> {} priority", - Self::IDENTIFIER, - data.call_info.messages_call_info().lane_id(), - data.relayer, - bundled_messages, - priority_boost, + id_provider=%Self::IDENTIFIER, + lane_id=?data.call_info.messages_call_info().lane_id(), + relayer=?data.relayer, + %bundled_messages, + %priority_boost, + "Has boosted priority of message delivery transaction of relayer" ); let validity = valid_transaction.build()?; @@ -370,12 +369,12 @@ where _len: usize, ) -> Result { Ok(val.inspect(|data| { - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: parsed bridge transaction in prepare: {:?}", - Self::IDENTIFIER, - data.call_info.messages_call_info().lane_id(), - data.call_info, + id_provider=%Self::IDENTIFIER, + lane_id=?data.call_info.messages_call_info().lane_id(), + call_info=?data.call_info, + "Parsed bridge transaction in prepare" ); })) } @@ -399,13 +398,13 @@ where reward, ); - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: has registered reward: {:?} for {:?}", - Self::IDENTIFIER, - lane_id, - reward, - relayer, + id_provider=%Self::IDENTIFIER, + ?lane_id, + ?relayer, + ?reward, + "Has registered reward" ); }, RelayerAccountAction::Slash(relayer, slash_account) => @@ -437,12 +436,12 @@ where if !MessagesCallHelper::::was_successful( messages_call, ) { - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: relayer {:?} has submitted invalid messages call", - C::IdProvider::STR, - call_info.messages_call_info().lane_id(), - relayer, + id_provider=%C::IdProvider::STR, + lane_id=?call_info.messages_call_info().lane_id(), + ?relayer, + "Relayer has submitted invalid messages call" ); return false } diff --git a/bridges/modules/relayers/src/extension/parachain_adapter.rs b/bridges/modules/relayers/src/extension/parachain_adapter.rs index 122e7073632fa..7776cc8dbaed4 100644 --- a/bridges/modules/relayers/src/extension/parachain_adapter.rs +++ b/bridges/modules/relayers/src/extension/parachain_adapter.rs @@ -174,12 +174,12 @@ where if !SubmitParachainHeadsHelper::::was_successful(para_proof_info) { // we only refund relayer if all calls have updated chain state - log::trace!( + tracing::trace!( target: LOG_TARGET, - "{}.{:?}: relayer {:?} has submitted invalid parachain finality proof", - C::IdProvider::STR, - call_info.messages_call_info().lane_id(), - relayer, + id_provider=%C::IdProvider::STR, + lane_id=?call_info.messages_call_info().lane_id(), + ?relayer, + "Relayer has submitted invalid parachain finality proof" ); return false } diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index d2fe73d534b89..d771242306b99 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -157,12 +157,12 @@ pub mod pallet { } else if let Some(to_reserve) = required_stake.checked_sub(®istration.stake) { T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| { - log::trace!( + tracing::trace!( target: LOG_TARGET, - "Failed to reserve {:?} on relayer {:?} account: {:?}", - to_reserve, - relayer, - e, + error=?e, + ?relayer, + ?to_reserve, + "Failed to reserve on relayer account" ); Error::::FailedToReserve @@ -170,7 +170,7 @@ pub mod pallet { } registration.stake = required_stake; - log::trace!(target: LOG_TARGET, "Successfully registered relayer: {:?}", relayer); + tracing::trace!(target: LOG_TARGET, ?relayer, "Successfully registered relayer"); Self::deposit_event(Event::::RegistrationUpdated { relayer: relayer.clone(), registration, @@ -211,7 +211,7 @@ pub mod pallet { Self::do_unreserve(&relayer, registration.stake)?; } - log::trace!(target: LOG_TARGET, "Successfully deregistered relayer: {:?}", relayer); + tracing::trace!(target: LOG_TARGET, ?relayer, "Successfully deregistered relayer"); Self::deposit_event(Event::::Deregistered { relayer: relayer.clone() }); *maybe_registration = None; @@ -278,14 +278,14 @@ pub mod pallet { beneficiary.clone(), ) .map_err(|e| { - log::error!( + tracing::error!( target: LOG_TARGET, - "Failed to pay ({:?} / {:?}) rewards to {:?}(beneficiary: {:?}), error: {:?}", - reward_kind, - reward_balance, - relayer, - beneficiary, - e, + error=?e, + ?relayer, + ?reward_kind, + ?reward_balance, + ?beneficiary, + "Failed to pay rewards" ); Error::::FailedToPayReward })?; @@ -338,10 +338,10 @@ pub mod pallet { let registration = match RegisteredRelayers::::take(relayer) { Some(registration) => registration, None => { - log::trace!( + tracing::trace!( target: crate::LOG_TARGET, - "Cannot slash unregistered relayer {:?}", - relayer, + ?relayer, + "Cannot slash unregistered relayer" ); return; @@ -355,23 +355,22 @@ pub mod pallet { registration.stake, ) { Ok(failed_to_slash) if failed_to_slash.is_zero() => { - log::trace!( + tracing::trace!( target: crate::LOG_TARGET, - "Relayer account {:?} has been slashed for {:?}. Funds were deposited to {:?}", - relayer, - registration.stake, - slash_destination, + ?relayer, + amount=?registration.stake, + ?slash_destination, + "Relayer account has been slashed. Funds were deposited." ); }, Ok(failed_to_slash) => { - log::trace!( + tracing::trace!( target: crate::LOG_TARGET, - "Relayer account {:?} has been partially slashed for {:?}. Funds were deposited to {:?}. \ - Failed to slash: {:?}", - relayer, - registration.stake, - slash_destination, - failed_to_slash, + ?relayer, + amount=?registration.stake, + ?slash_destination, + ?failed_to_slash, + "Relayer account has been partially slashed. Funds were deposited.", ); }, Err(e) => { @@ -379,15 +378,14 @@ pub mod pallet { // it may fail if there's no beneficiary account. For us, it means that this // account must exist before we'll deploy the bridge - log::debug!( + tracing::debug!( target: crate::LOG_TARGET, - "Failed to slash relayer account {:?}: {:?}. Maybe beneficiary account doesn't exist? \ - Beneficiary: {:?}, amount: {:?}, failed to slash: {:?}", - relayer, - e, - slash_destination, - registration.stake, - registration.stake, + error=?e, + ?relayer, + beneficiary=?slash_destination, + amount=?registration.stake, + failed_to_slash=?registration.stake, + "Failed to slash relayer account. Maybe beneficiary account doesn't exist?" ); }, } @@ -416,12 +414,12 @@ pub mod pallet { old_reward.unwrap_or_else(Zero::zero).saturating_add(reward_balance); *old_reward = Some(new_reward); - log::trace!( + tracing::trace!( target: crate::LOG_TARGET, - "Relayer {:?} can now claim reward for serving payer {:?}: {:?}", - relayer, - reward_kind, - new_reward, + ?relayer, + ?reward_kind, + ?new_reward, + "Relayer can now claim reward for serving payer" ); Self::deposit_event(Event::::RewardRegistered { @@ -455,12 +453,12 @@ pub mod pallet { fn do_unreserve(relayer: &T::AccountId, amount: T::Balance) -> DispatchResult { let failed_to_unreserve = T::StakeAndSlash::unreserve(relayer, amount); if !failed_to_unreserve.is_zero() { - log::trace!( + tracing::trace!( target: LOG_TARGET, - "Failed to unreserve {:?}/{:?} on relayer {:?} account", - failed_to_unreserve, - amount, - relayer, + ?relayer, + ?failed_to_unreserve, + ?amount, + "Failed to unreserve on relayer account", ); fail!(Error::::FailedToUnreserve) diff --git a/bridges/modules/relayers/src/migration.rs b/bridges/modules/relayers/src/migration.rs index 11a809e5d335e..1c2d2355ec707 100644 --- a/bridges/modules/relayers/src/migration.rs +++ b/bridges/modules/relayers/src/migration.rs @@ -191,12 +191,12 @@ pub mod v1 { old_reward.unwrap_or_else(Zero::zero).saturating_add(reward_balance); *old_reward = Some(new_reward); - log::trace!( + tracing::trace!( target: crate::LOG_TARGET, - "Relayer {:?} can now claim reward for serving payer {:?}: {:?}", - relayer, - rewards_account_params, - new_reward, + ?relayer, + ?rewards_account_params, + ?new_reward, + "Relayer can now claim reward" ); }, ); @@ -252,7 +252,7 @@ pub mod v1 { ConstU32<{ u32::MAX }>, > = BoundedBTreeMap::new(); for (key1, key2, reward) in v0::RelayerRewards::::iter() { - log::info!(target: LOG_TARGET, "Reward to migrate: {key1:?}::{key2:?} - {reward:?}"); + tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Reward to migrate"); rewards = rewards .try_mutate(|inner| { inner @@ -262,7 +262,7 @@ pub mod v1 { }) .unwrap(); } - log::info!(target: LOG_TARGET, "Found total rewards to migrate: {rewards:?}"); + tracing::info!(target: LOG_TARGET, ?rewards, "Found total rewards to migrate"); Ok(rewards.encode()) } @@ -286,7 +286,7 @@ pub mod v1 { ConstU32<{ u32::MAX }>, > = BoundedBTreeMap::new(); for (key1, key2, reward) in v1::RelayerRewards::::iter() { - log::info!(target: LOG_TARGET, "Migrated rewards: {key1:?}::{key2:?} - {reward:?}"); + tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Migrated rewards"); rewards_after = rewards_after .try_mutate(|inner| { inner @@ -296,14 +296,14 @@ pub mod v1 { }) .unwrap(); } - log::info!(target: LOG_TARGET, "Found total migrated rewards: {rewards_after:?}"); + tracing::info!(target: LOG_TARGET, ?rewards_after, "Found total migrated rewards"); frame_support::ensure!( rewards_before == rewards_after, "The rewards were not migrated correctly!." ); - log::info!(target: LOG_TARGET, "migrated all."); + tracing::info!(target: LOG_TARGET, "migrated all."); Ok(()) } } @@ -382,7 +382,7 @@ pub mod v2 { > = BoundedBTreeMap::new(); for (key1, key2, reward) in v1::RelayerRewards::::iter() { let new_key2: T::Reward = key2.into(); - log::info!(target: LOG_TARGET, "Reward to migrate: {key1:?}::{key2:?}->{new_key2:?} - {reward:?}"); + tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?new_key2, ?reward, "Reward to migrate"); rewards = rewards .try_mutate(|inner| { inner @@ -392,7 +392,7 @@ pub mod v2 { }) .unwrap(); } - log::info!(target: LOG_TARGET, "Found total rewards to migrate: {rewards:?}"); + tracing::info!(target: LOG_TARGET, ?rewards, "Found total rewards to migrate"); Ok(rewards.encode()) } @@ -416,7 +416,7 @@ pub mod v2 { ConstU32<{ u32::MAX }>, > = BoundedBTreeMap::new(); for (key1, key2, reward) in v2::RelayerRewards::::iter() { - log::info!(target: LOG_TARGET, "Migrated rewards: {key1:?}::{key2:?} - {reward:?}"); + tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Migrated rewards"); rewards_after = rewards_after .try_mutate(|inner| { inner @@ -426,14 +426,14 @@ pub mod v2 { }) .unwrap(); } - log::info!(target: LOG_TARGET, "Found total migrated rewards: {rewards_after:?}"); + tracing::info!(target: LOG_TARGET, ?rewards_after, "Found total migrated rewards"); frame_support::ensure!( rewards_before == rewards_after, "The rewards were not migrated correctly!." ); - log::info!(target: LOG_TARGET, "migrated all."); + tracing::info!(target: LOG_TARGET, "migrated all."); Ok(()) } } diff --git a/prdoc/pr_9381.prdoc b/prdoc/pr_9381.prdoc new file mode 100644 index 0000000000000..a3dbed26a78c2 --- /dev/null +++ b/prdoc/pr_9381.prdoc @@ -0,0 +1,8 @@ +title: Replace `log` with `tracing` on `pallet-bridge-relayers` +doc: +- audience: Runtime Dev + description: This PR replaces `log` with `tracing` instrumentation on `pallet-bridge-relayers` + by providing structured logging. +crates: +- name: pallet-bridge-relayers + bump: minor From ae8848977b5f972268de584b6f30e1b47b547db8 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Thu, 21 Aug 2025 16:46:57 +0200 Subject: [PATCH 11/16] [Backport] Version bumps and prdoc reordering from stable2506-1 (#9529) This PR backport regular version bumps and prdocs reordering from the stable2506 branch back to master --- cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 2 +- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../runtimes/collectives/collectives-westend/src/lib.rs | 2 +- cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs | 2 +- .../parachains/runtimes/coretime/coretime-westend/src/lib.rs | 2 +- cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs | 2 +- cumulus/parachains/runtimes/people/people-rococo/src/lib.rs | 2 +- cumulus/parachains/runtimes/people/people-westend/src/lib.rs | 2 +- cumulus/polkadot-omni-node/lib/src/nodes/mod.rs | 2 +- polkadot/node/primitives/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- prdoc/{ => stable2506-1}/pr_8838.prdoc | 0 prdoc/{ => stable2506-1}/pr_8857.prdoc | 0 prdoc/{ => stable2506-1}/pr_9179.prdoc | 0 prdoc/{ => stable2506-1}/pr_9189.prdoc | 0 prdoc/{ => stable2506-1}/pr_9195.prdoc | 0 prdoc/{ => stable2506-1}/pr_9250.prdoc | 0 prdoc/{ => stable2506-1}/pr_9281.prdoc | 0 prdoc/{ => stable2506-1}/pr_9338.prdoc | 0 prdoc/{ => stable2506-1}/pr_9354.prdoc | 0 prdoc/{ => stable2506-1}/pr_9355.prdoc | 0 prdoc/{ => stable2506-1}/pr_9445.prdoc | 0 prdoc/{ => stable2506-1}/pr_9489.prdoc | 0 26 files changed, 14 insertions(+), 14 deletions(-) rename prdoc/{ => stable2506-1}/pr_8838.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_8857.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9179.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9189.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9195.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9250.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9281.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9338.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9354.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9355.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9445.prdoc (100%) rename prdoc/{ => stable2506-1}/pr_9489.prdoc (100%) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index c26c17fbb7adf..abb842085d437 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -129,7 +129,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("statemine"), impl_name: alloc::borrow::Cow::Borrowed("statemine"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 46094e233b1c7..f0ef5432aeda7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -145,7 +145,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("westmint"), impl_name: alloc::borrow::Cow::Borrowed("westmint"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 2d951af2d2cde..d91dd0adcdfb6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -253,7 +253,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("bridge-hub-rococo"), impl_name: alloc::borrow::Cow::Borrowed("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 99742ceed289f..eaa58ac1b62ed 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -243,7 +243,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("bridge-hub-westend"), impl_name: alloc::borrow::Cow::Borrowed("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 97198c0a226eb..cd89e9151c635 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -129,7 +129,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("collectives-westend"), impl_name: alloc::borrow::Cow::Borrowed("collectives-westend"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 69ce1e0d5aeda..dfefc339e6a76 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -159,7 +159,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("coretime-rococo"), impl_name: alloc::borrow::Cow::Borrowed("coretime-rococo"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 15adbad1cd740..0a60b6660e46b 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -159,7 +159,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("coretime-westend"), impl_name: alloc::borrow::Cow::Borrowed("coretime-westend"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 3bfd427febb57..617d8f1174a7a 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -103,7 +103,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("glutton-westend"), impl_name: alloc::borrow::Cow::Borrowed("glutton-westend"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 259706b52cf2f..9e20bf64f91cf 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -146,7 +146,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("people-rococo"), impl_name: alloc::borrow::Cow::Borrowed("people-rococo"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index b0430eff34259..cbdca464f860b 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -149,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("people-westend"), impl_name: alloc::borrow::Cow::Borrowed("people-westend"), authoring_version: 1, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs b/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs index b310e30c92c58..0b27038ee318d 100644 --- a/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs @@ -24,7 +24,7 @@ use sc_service::{Configuration, TaskManager}; /// The current node version for cumulus official binaries, which takes the basic /// SemVer form `..`. It should correspond to the latest /// `polkadot` version of a stable release. -pub const NODE_VERSION: &'static str = "1.19.0"; +pub const NODE_VERSION: &'static str = "1.19.1"; /// Trait that extends the `DynNodeSpec` trait with manual seal related logic. /// diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 3a187ce5e03b2..10791dc283daf 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -62,7 +62,7 @@ pub use disputes::{ /// relatively rare. /// /// The associated worker binaries should use the same version as the node that spawns them. -pub const NODE_VERSION: &'static str = "1.19.0"; +pub const NODE_VERSION: &'static str = "1.19.1"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 7a7c046555d65..78e943f0c179a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -184,7 +184,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("rococo"), impl_name: alloc::borrow::Cow::Borrowed("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index b65cb71d6899e..2724d102da2e2 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -174,7 +174,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: alloc::borrow::Cow::Borrowed("westend"), impl_name: alloc::borrow::Cow::Borrowed("parity-westend"), authoring_version: 2, - spec_version: 1_019_002, + spec_version: 1_019_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 27, diff --git a/prdoc/pr_8838.prdoc b/prdoc/stable2506-1/pr_8838.prdoc similarity index 100% rename from prdoc/pr_8838.prdoc rename to prdoc/stable2506-1/pr_8838.prdoc diff --git a/prdoc/pr_8857.prdoc b/prdoc/stable2506-1/pr_8857.prdoc similarity index 100% rename from prdoc/pr_8857.prdoc rename to prdoc/stable2506-1/pr_8857.prdoc diff --git a/prdoc/pr_9179.prdoc b/prdoc/stable2506-1/pr_9179.prdoc similarity index 100% rename from prdoc/pr_9179.prdoc rename to prdoc/stable2506-1/pr_9179.prdoc diff --git a/prdoc/pr_9189.prdoc b/prdoc/stable2506-1/pr_9189.prdoc similarity index 100% rename from prdoc/pr_9189.prdoc rename to prdoc/stable2506-1/pr_9189.prdoc diff --git a/prdoc/pr_9195.prdoc b/prdoc/stable2506-1/pr_9195.prdoc similarity index 100% rename from prdoc/pr_9195.prdoc rename to prdoc/stable2506-1/pr_9195.prdoc diff --git a/prdoc/pr_9250.prdoc b/prdoc/stable2506-1/pr_9250.prdoc similarity index 100% rename from prdoc/pr_9250.prdoc rename to prdoc/stable2506-1/pr_9250.prdoc diff --git a/prdoc/pr_9281.prdoc b/prdoc/stable2506-1/pr_9281.prdoc similarity index 100% rename from prdoc/pr_9281.prdoc rename to prdoc/stable2506-1/pr_9281.prdoc diff --git a/prdoc/pr_9338.prdoc b/prdoc/stable2506-1/pr_9338.prdoc similarity index 100% rename from prdoc/pr_9338.prdoc rename to prdoc/stable2506-1/pr_9338.prdoc diff --git a/prdoc/pr_9354.prdoc b/prdoc/stable2506-1/pr_9354.prdoc similarity index 100% rename from prdoc/pr_9354.prdoc rename to prdoc/stable2506-1/pr_9354.prdoc diff --git a/prdoc/pr_9355.prdoc b/prdoc/stable2506-1/pr_9355.prdoc similarity index 100% rename from prdoc/pr_9355.prdoc rename to prdoc/stable2506-1/pr_9355.prdoc diff --git a/prdoc/pr_9445.prdoc b/prdoc/stable2506-1/pr_9445.prdoc similarity index 100% rename from prdoc/pr_9445.prdoc rename to prdoc/stable2506-1/pr_9445.prdoc diff --git a/prdoc/pr_9489.prdoc b/prdoc/stable2506-1/pr_9489.prdoc similarity index 100% rename from prdoc/pr_9489.prdoc rename to prdoc/stable2506-1/pr_9489.prdoc From 0aa6a1169d8c362106e1c493e31a6568982b88ed Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:59:14 +0300 Subject: [PATCH 12/16] `polkadot-omni-node`: fixes and changes related to `GetParachainInfo` (#9201) # Description - log::info! the error of accessing `GetParachainInfo::parachain_id()` runtime api if any, before reading the `para_id` from the chain specification (relevant for debugging). - removes comments/deprecation notices throughout the code that introduce `para-id` flag removal (from chain-spec-builder and support for parsing it from chain specifications) Closes #9217 ## Integration N/A ## Review Notes N/A --------- Signed-off-by: Iulian Barbu Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Sebastian Kunert Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- cumulus/polkadot-omni-node/README.md | 10 +-- cumulus/polkadot-omni-node/lib/src/cli.rs | 2 +- .../lib/src/common/chain_spec.rs | 73 ++++++++----------- .../polkadot-omni-node/lib/src/common/spec.rs | 36 +++++---- .../src/chain_spec/asset_hubs.rs | 26 ++----- .../src/chain_spec/bridge_hubs.rs | 25 +------ .../src/chain_spec/collectives.rs | 4 +- .../src/chain_spec/coretime.rs | 27 ++++--- .../src/chain_spec/glutton.rs | 7 +- .../src/chain_spec/penpal.rs | 4 +- .../src/chain_spec/people.rs | 31 ++------ .../src/chain_spec/rococo_parachain.rs | 4 +- .../src/chain_spec/yet_another_parachain.rs | 2 +- prdoc/pr_9201.prdoc | 16 ++++ .../utils/chain-spec-builder/README.docify.md | 21 +++--- .../bin/utils/chain-spec-builder/README.md | 21 +++--- .../bin/utils/chain-spec-builder/src/lib.rs | 20 +---- 17 files changed, 134 insertions(+), 195 deletions(-) create mode 100644 prdoc/pr_9201.prdoc diff --git a/cumulus/polkadot-omni-node/README.md b/cumulus/polkadot-omni-node/README.md index 0d3fdaaf4c2fe..9031ec375dee3 100644 --- a/cumulus/polkadot-omni-node/README.md +++ b/cumulus/polkadot-omni-node/README.md @@ -46,11 +46,11 @@ local variants are available only for a build of `polkadot-omni-node` with `westend-native` and `rococo-native` features respectively. - -Additionaly, although deprecated, the `--para-id` flag can still be used to set the JSON key named -`para_id`. The removal of the flag will happen starting with `stable2512`. The alternative of not using -it is to implement the `cumulus_primitives_core::GetParachainInfo` runtime API for the runtime, and -upgrade it on-chain as well, to be compatible with nodes released starting with `stable2512`. +Additionaly, the `--para-id` flag can be used to set the JSON key named `para_id`. This flag is used +by nodes to determine the parachain id, and it is especially useful when the parachain id can not be +fetched from the runtime, when the state points to a runtime that does not implement the +`cumulus_primitives_core::GetParachainInfo` runtime API. It is recommended for runtimes to implement +the runtime API and be upgraded on chain. Example command bellow: diff --git a/cumulus/polkadot-omni-node/lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs index 5f9f949ce7268..af9f6c00dd7d8 100644 --- a/cumulus/polkadot-omni-node/lib/src/cli.rs +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -316,7 +316,7 @@ impl RelayChainCli { let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()); let extension = Extensions::try_get(&*para_config.chain_spec); - let chain_id = extension.map(|e| e.relay_chain.clone()); + let chain_id = extension.map(|e| e.relay_chain()); let base_path = para_config.base_path.path().join("polkadot"); Self { base, chain_id, base_path: Some(base_path), _phantom: Default::default() } diff --git a/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs b/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs index 7107045c0f407..2a55d75785238 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs @@ -32,59 +32,52 @@ pub struct DiskChainSpecLoader; impl LoadSpec for DiskChainSpecLoader { fn load_spec(&self, path: &str) -> Result, String> { - Ok(Box::new(DeprecatedGenericChainSpec::from_json_file(path.into())?)) - } -} - -/// Generic extensions for Parachain ChainSpecs. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecExtension)] -pub struct Extensions { - /// The relay chain of the Parachain. - #[serde(alias = "relayChain", alias = "RelayChain")] - pub relay_chain: String, -} - -impl Extensions { - /// Try to get the extension from the given `ChainSpec`. - pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { - sc_chain_spec::get_extension(chain_spec.extensions()) + Ok(Box::new(GenericChainSpec::from_json_file(path.into())?)) } } /// Generic extensions for Parachain ChainSpecs used for extracting the extensions from chain specs. -/// This is also used only while `para_id` is around the corner. -// TODO: https://github.com/paritytech/polkadot-sdk/issues/8747 -// TODO: https://github.com/paritytech/polkadot-sdk/issues/8740 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecExtension)] -pub struct DeprecatedExtensions { +pub struct Extensions { /// The relay chain of the Parachain. It is kept here only for compatibility reasons until /// people migrate to using the new `Extensions` struct and associated logic in the node /// corresponding to pulling the parachain id from the runtime. #[serde(alias = "relayChain", alias = "RelayChain")] - pub relay_chain: String, + relay_chain: String, /// The id of the Parachain. #[serde(alias = "paraId", alias = "ParaId")] - #[deprecated( - note = "The para_id information is not required anymore and will be removed starting with `stable2512`. Runtimes must implement a new API called `cumulus_primitives_core::GetParachainInfo` to still be compatible with node versions starting with `stable2512`." - )] - pub para_id: Option, + para_id: Option, } -impl DeprecatedExtensions { +impl Extensions { /// Try to get the extension from the given `ChainSpec`. pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { sc_chain_spec::get_extension(chain_spec.extensions()) } + + /// Create the extensions only with the relay_chain. + pub fn new_with_relay_chain(relay_chain: String) -> Self { + Extensions { relay_chain, para_id: None } + } + + /// Initialize extensions based on given parameters. + pub fn new(relay_chain: String, para_id: u32) -> Self { + Extensions { relay_chain, para_id: Some(para_id) } + } + + /// Para id field getter + pub fn para_id(&self) -> Option { + self.para_id + } + + /// Relay chain field getter + pub fn relay_chain(&self) -> String { + self.relay_chain.clone() + } } /// Generic chain spec for all polkadot-parachain runtimes pub type GenericChainSpec = sc_service::GenericChainSpec; -/// Generic chain spec which keeps chain spec loading compatible for those who provide -/// `para_id` extension instead of implementing the runtime API -/// `cumulus_primitives_core::GetParachainInfo`. -// TODO: https://github.com/paritytech/polkadot-sdk/issues/8747 -// TODO: https://github.com/paritytech/polkadot-sdk/issues/8740 -pub type DeprecatedGenericChainSpec = sc_service::GenericChainSpec; #[cfg(test)] mod tests { @@ -97,21 +90,13 @@ mod tests { let pascal_case = r#"{"RelayChain":"relay","ParaId":1}"#; let para_id_missing = r#"{"RelayChain":"westend"}"#; - let camel_case_extension: DeprecatedExtensions = serde_json::from_str(camel_case).unwrap(); - let snake_case_extension: DeprecatedExtensions = serde_json::from_str(snake_case).unwrap(); - let pascal_case_extension: DeprecatedExtensions = - serde_json::from_str(pascal_case).unwrap(); + let camel_case_extension: Extensions = serde_json::from_str(camel_case).unwrap(); + let snake_case_extension: Extensions = serde_json::from_str(snake_case).unwrap(); + let pascal_case_extension: Extensions = serde_json::from_str(pascal_case).unwrap(); let missing_paraid_extension: Extensions = serde_json::from_str(para_id_missing).unwrap(); - let missing_paraid_deprecated: DeprecatedExtensions = - serde_json::from_str(para_id_missing).unwrap(); assert_eq!(camel_case_extension, snake_case_extension); assert_eq!(snake_case_extension, pascal_case_extension); assert_eq!(missing_paraid_extension.relay_chain, "westend".to_string()); - - // TODO: remove it once `para_id` is removed: https://github.com/paritytech/polkadot-sdk/issues/8740 - assert_eq!(missing_paraid_deprecated.relay_chain, "westend".to_string()); - #[allow(deprecated)] - let test = missing_paraid_deprecated.para_id.is_none(); - assert!(test); + assert!(missing_paraid_extension.para_id.is_none()); } } diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs index 5331c7b461031..f0d4cc0e0a88d 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -15,7 +15,7 @@ // limitations under the License. use crate::{ - chain_spec::DeprecatedExtensions, + chain_spec::Extensions, common::{ command::NodeCommandRunner, rpc::BuildRpcExtensions, @@ -51,7 +51,7 @@ use sc_telemetry::{TelemetryHandle, TelemetryWorker}; use sc_tracing::tracing::Instrument; use sc_transaction_pool::TransactionPoolHandle; use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_keystore::KeystorePtr; use sp_runtime::traits::AccountIdConversion; use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; @@ -157,19 +157,27 @@ pub(crate) trait BaseNodeSpec { parachain_config: &Configuration, ) -> Option { let best_hash = client.chain_info().best_hash; - let para_id = if let Ok(para_id) = client.runtime_api().parachain_id(best_hash) { - para_id + let para_id = if client + .runtime_api() + .has_api::>(best_hash) + .ok() + .filter(|has_api| *has_api) + .is_some() + { + client + .runtime_api() + .parachain_id(best_hash) + .inspect_err(|err| { + log::error!( + "`cumulus_primitives_core::GetParachainInfo` runtime API call errored with {}", + err + ); + }) + .ok()? } else { - // TODO: remove this once `para_id` extension is removed: https://github.com/paritytech/polkadot-sdk/issues/8740 - #[allow(deprecated)] - let id = ParaId::from( - DeprecatedExtensions::try_get(&*parachain_config.chain_spec) - .and_then(|ext| ext.para_id)?, - ); - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8747 - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8740 - log::info!("Deprecation notice: the parachain id was provided via the chain spec. This way of providing the parachain id to the node is not recommended. The alternative is to implement the `cumulus_primitives_core::GetParachainInfo` runtime API in the runtime, and upgrade it on-chain. Starting with `stable2512` providing the parachain id via the chain spec will not be supported anymore."); - id + ParaId::from( + Extensions::try_get(&*parachain_config.chain_spec).and_then(|ext| ext.para_id())?, + ) }; let parachain_account = diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index ead445979bf1a..adae8dc30962f 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -25,7 +25,7 @@ pub fn asset_hub_westend_development_config() -> GenericChainSpec { GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend".into() }, + Extensions::new_with_relay_chain("westend".into()), ) .with_name("Westend Asset Hub Development") .with_id("asset-hub-westend-dev") @@ -43,7 +43,7 @@ pub fn asset_hub_westend_local_config() -> GenericChainSpec { GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend-local".into() }, + Extensions::new_with_relay_chain("westend-local".into()), ) .with_name("Westend Asset Hub Local") .with_id("asset-hub-westend-local") @@ -61,7 +61,7 @@ pub fn asset_hub_westend_config() -> GenericChainSpec { GenericChainSpec::builder( asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend".into() }, + Extensions::new_with_relay_chain("westend".into()), ) .with_name("Westend Asset Hub") .with_id("asset-hub-westend") @@ -80,7 +80,6 @@ pub fn asset_hub_rococo_development_config() -> GenericChainSpec { properties, "Rococo Asset Hub Development", "asset-hub-rococo-dev", - 1000, ) } @@ -88,21 +87,15 @@ fn asset_hub_rococo_like_development_config( properties: sc_chain_spec::Properties, name: &str, chain_id: &str, - para_id: u32, ) -> GenericChainSpec { GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo-dev".into() }, + Extensions::new_with_relay_chain("rococo-dev".into()), ) .with_name(name) .with_id(chain_id) .with_chain_type(ChainType::Local) .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } @@ -116,7 +109,6 @@ pub fn asset_hub_rococo_local_config() -> GenericChainSpec { properties, "Rococo Asset Hub Local", "asset-hub-rococo-local", - 1000, ) } @@ -124,21 +116,15 @@ fn asset_hub_rococo_like_local_config( properties: sc_chain_spec::Properties, name: &str, chain_id: &str, - para_id: u32, ) -> GenericChainSpec { GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo-local".into() }, + Extensions::new_with_relay_chain("rococo-local".into()), ) .with_name(name) .with_id(chain_id) .with_chain_type(ChainType::Local) .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } @@ -149,7 +135,7 @@ pub fn asset_hub_rococo_genesis_config() -> GenericChainSpec { properties.insert("tokenDecimals".into(), 12.into()); GenericChainSpec::builder( asset_hub_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo".into() }, + Extensions::new_with_relay_chain("rococo".into()), ) .with_name("Rococo Asset Hub") .with_id("asset-hub-rococo") diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 2adeaf2c99215..4927dcba7be05 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -14,7 +14,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use cumulus_primitives_core::ParaId; use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::{ChainSpec, ChainType}; use std::str::FromStr; @@ -77,14 +76,12 @@ impl BridgeHubRuntimeType { westend::BRIDGE_HUB_WESTEND_LOCAL, "Westend BridgeHub Local", "westend-local", - ParaId::new(1002), ChainType::Local, ))), BridgeHubRuntimeType::WestendDevelopment => Ok(Box::new(westend::local_config( westend::BRIDGE_HUB_WESTEND_DEVELOPMENT, "Westend BridgeHub Development", "westend-dev", - ParaId::new(1002), ChainType::Development, ))), BridgeHubRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( @@ -94,7 +91,6 @@ impl BridgeHubRuntimeType { rococo::BRIDGE_HUB_ROCOCO_LOCAL, "Rococo BridgeHub Local", "rococo-local", - ParaId::new(1013), |_| (), ChainType::Local, ))), @@ -102,7 +98,6 @@ impl BridgeHubRuntimeType { rococo::BRIDGE_HUB_ROCOCO_DEVELOPMENT, "Rococo BridgeHub Development", "rococo-dev", - ParaId::new(1013), |_| (), ChainType::Development, ))), @@ -126,7 +121,7 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup pub mod rococo { - use super::{ChainType, ParaId}; + use super::ChainType; use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_ROCOCO: &str = "bridge-hub-rococo"; @@ -137,7 +132,6 @@ pub mod rococo { id: &str, chain_name: &str, relay_chain: &str, - para_id: ParaId, modify_props: ModifyProperties, chain_type: ChainType, ) -> GenericChainSpec { @@ -151,7 +145,7 @@ pub mod rococo { GenericChainSpec::builder( bridge_hub_rococo_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string() }, + Extensions::new_with_relay_chain(relay_chain.to_string()), ) .with_name(chain_name) .with_id(super::ensure_id(id).expect("invalid id")) @@ -161,11 +155,6 @@ pub mod rococo { ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, _ => panic!("chain_type: {chain_type:?} not supported here!"), }) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } @@ -179,7 +168,7 @@ pub mod kusama { /// Sub-module for Westend setup. pub mod westend { - use super::{ChainType, ParaId}; + use super::ChainType; use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_WESTEND: &str = "bridge-hub-westend"; @@ -190,7 +179,6 @@ pub mod westend { id: &str, chain_name: &str, relay_chain: &str, - para_id: ParaId, chain_type: ChainType, ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); @@ -200,7 +188,7 @@ pub mod westend { GenericChainSpec::builder( bridge_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!"), - Extensions { relay_chain: relay_chain.to_string() }, + Extensions::new_with_relay_chain(relay_chain.to_string()), ) .with_name(chain_name) .with_id(super::ensure_id(id).expect("invalid id")) @@ -210,11 +198,6 @@ pub mod westend { ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, _ => panic!("chain_type: {chain_type:?} not supported here!"), }) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 5d2d57224f7b1..1e9a4489c99b0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -27,7 +27,7 @@ pub fn collectives_westend_development_config() -> GenericChainSpec { GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend-dev".into() }, + Extensions::new_with_relay_chain("westend-dev".into()), ) .with_name("Westend Collectives Development") .with_id("collectives_westend_dev") @@ -48,7 +48,7 @@ pub fn collectives_westend_local_config() -> GenericChainSpec { GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend-local".into() }, + Extensions::new_with_relay_chain("westend-local".into()), ) .with_name("Westend Collectives Local") .with_id("collectives_westend_local") diff --git a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs index 47cc66bdd4eca..e5cc4891d1f02 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs @@ -168,17 +168,20 @@ pub mod rococo { .expect("WASM binary was not built, please build it!") }; - GenericChainSpec::builder(wasm_binary, Extensions { relay_chain: relay_chain.to_string() }) - .with_name(&chain_name) - .with_id(runtime_type.into()) - .with_chain_type(chain_type.clone()) - .with_genesis_config_preset_name(match chain_type { - ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, - ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, - _ => panic!("chain_type: {chain_type:?} not supported here!"), - }) - .with_properties(properties) - .build() + GenericChainSpec::builder( + wasm_binary, + Extensions::new_with_relay_chain(relay_chain.to_string()), + ) + .with_name(&chain_name) + .with_id(runtime_type.into()) + .with_chain_type(chain_type.clone()) + .with_genesis_config_preset_name(match chain_type { + ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, + ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, + _ => panic!("chain_type: {chain_type:?} not supported here!"), + }) + .with_properties(properties) + .build() } } @@ -205,7 +208,7 @@ pub mod westend { GenericChainSpec::builder( coretime_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string() }, + Extensions::new_with_relay_chain(relay_chain.to_string()), ) .with_name(&chain_name) .with_id(runtime_type.into()) diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 346075207836c..71f12ca3af969 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -29,7 +29,7 @@ pub fn glutton_westend_config( GenericChainSpec::builder( glutton_westend_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.into() }, + Extensions::new_with_relay_chain(relay_chain.into()), ) .with_name(&chain_type_name(para_id, &chain_type)) .with_id(&chain_id(para_id, &chain_type)) @@ -39,11 +39,6 @@ pub fn glutton_westend_config( ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, _ => panic!("chain_type: {chain_type:?} not supported here!"), }) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .build() } diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index c82f5c57f4b15..2d9cda5b68f42 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -27,9 +27,7 @@ pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec GenericChainSpec::builder( penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: relay_chain.into(), // You MUST set this to the correct network! - }, + Extensions::new_with_relay_chain(relay_chain.into()), ) .with_name("Penpal Parachain") .with_id(&format!("penpal-{}", relay_chain.replace("-local", ""))) diff --git a/cumulus/polkadot-parachain/src/chain_spec/people.rs b/cumulus/polkadot-parachain/src/chain_spec/people.rs index fcd25d8127dbd..6735a15973df9 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/people.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/people.rs @@ -14,7 +14,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use cumulus_primitives_core::ParaId; use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::{ChainSpec, ChainType}; use std::str::FromStr; @@ -72,14 +71,12 @@ impl PeopleRuntimeType { rococo::PEOPLE_ROCOCO_LOCAL, "Rococo People Local", "rococo-local", - ParaId::new(1004), ChainType::Local, ))), PeopleRuntimeType::RococoDevelopment => Ok(Box::new(rococo::local_config( rococo::PEOPLE_ROCOCO_DEVELOPMENT, "Rococo People Development", "rococo-development", - ParaId::new(1004), ChainType::Development, ))), PeopleRuntimeType::Westend => Ok(Box::new(GenericChainSpec::from_json_bytes( @@ -89,14 +86,12 @@ impl PeopleRuntimeType { westend::PEOPLE_WESTEND_LOCAL, "Westend People Local", "westend-local", - ParaId::new(1004), ChainType::Local, ))), PeopleRuntimeType::WestendDevelopment => Ok(Box::new(westend::local_config( westend::PEOPLE_WESTEND_DEVELOPMENT, "Westend People Development", "westend-development", - ParaId::new(1004), ChainType::Development, ))), other => Err(std::format!( @@ -122,7 +117,6 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup. pub mod rococo { - use super::ParaId; use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; @@ -131,10 +125,9 @@ pub mod rococo { pub(crate) const PEOPLE_ROCOCO_DEVELOPMENT: &str = "people-rococo-dev"; pub fn local_config( - id: &str, + spec_id: &str, chain_name: &str, relay_chain: &str, - para_id: ParaId, chain_type: ChainType, ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); @@ -145,21 +138,16 @@ pub mod rococo { GenericChainSpec::builder( people_rococo_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string() }, + Extensions::new_with_relay_chain(relay_chain.to_string()), ) .with_name(chain_name) - .with_id(super::ensure_id(id).expect("invalid id")) + .with_id(super::ensure_id(spec_id).expect("invalid id")) .with_chain_type(chain_type.clone()) .with_genesis_config_preset_name(match chain_type { ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, _ => panic!("chain_type: {chain_type:?} not supported here!"), }) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } @@ -167,7 +155,6 @@ pub mod rococo { /// Sub-module for Westend setup. pub mod westend { - use super::ParaId; use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; @@ -176,10 +163,9 @@ pub mod westend { pub(crate) const PEOPLE_WESTEND_DEVELOPMENT: &str = "people-westend-dev"; pub fn local_config( - id: &str, + spec_id: &str, chain_name: &str, relay_chain: &str, - para_id: ParaId, chain_type: ChainType, ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); @@ -190,21 +176,16 @@ pub mod westend { GenericChainSpec::builder( people_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay_chain.to_string() }, + Extensions::new_with_relay_chain(relay_chain.to_string()), ) .with_name(chain_name) - .with_id(super::ensure_id(id).expect("invalid id")) + .with_id(super::ensure_id(spec_id).expect("invalid id")) .with_chain_type(chain_type.clone()) .with_genesis_config_preset_name(match chain_type { ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, _ => panic!("chain_type: {chain_type:?} not supported here!"), }) - .with_genesis_config_patch(serde_json::json!({ - "parachainInfo": { - "parachainId": para_id, - }, - })) .with_properties(properties) .build() } diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index 8d2dca95f111c..dc6a3b6666277 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -27,7 +27,7 @@ use sp_core::crypto::UncheckedInto; pub fn rococo_parachain_local_config() -> GenericChainSpec { GenericChainSpec::builder( rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo-local".into() }, + Extensions::new_with_relay_chain("rococo-local".into()), ) .with_name("Rococo Parachain Local") .with_id("local_testnet") @@ -39,7 +39,7 @@ pub fn rococo_parachain_local_config() -> GenericChainSpec { pub fn staging_rococo_parachain_local_config() -> GenericChainSpec { GenericChainSpec::builder( rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo-local".into() }, + Extensions::new_with_relay_chain("rococo-local".into()), ) .with_name("Staging Rococo Parachain Local") .with_id("staging_testnet") diff --git a/cumulus/polkadot-parachain/src/chain_spec/yet_another_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/yet_another_parachain.rs index fb1a6adfcdf2f..3905f8d62b7a0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/yet_another_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/yet_another_parachain.rs @@ -86,7 +86,7 @@ pub fn yet_another_parachain_config( GenericChainSpec::builder( yet_another_parachain_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: relay.into() }, + Extensions::new_with_relay_chain(relay.into()), ) .with_name("Yet Another Parachain") .with_id("yet_another_parachain") diff --git a/prdoc/pr_9201.prdoc b/prdoc/pr_9201.prdoc new file mode 100644 index 0000000000000..c08444c78683d --- /dev/null +++ b/prdoc/pr_9201.prdoc @@ -0,0 +1,16 @@ +title: '`polkadot-parachain`: fixes and changes related to GetParachainInfo' +doc: +- audience: Node Dev + description: |- + - Provides some updated to the asset-hub-westend-local chain specification, by adding appropriate genesis patch for parachainInfo. + - refactors the logic related to fetching `para_id` with the node, so that when failing to use `GetParachainInfo::parachain_id` we also get a log with the error (before defaulting to `para_id` extracted from chain spec). + - removes comments/deprecation notices throughout the code that introduce para-id flag removal (from chain-spec-builder and support for parsing it from chain specifications) +crates: +- name: polkadot-parachain-bin + bump: patch +- name: polkadot-omni-node-lib + bump: major +- name: polkadot-omni-node + bump: patch +- name: staging-chain-spec-builder + bump: patch diff --git a/substrate/bin/utils/chain-spec-builder/README.docify.md b/substrate/bin/utils/chain-spec-builder/README.docify.md index 091814bdc8043..1b0f78d278c55 100644 --- a/substrate/bin/utils/chain-spec-builder/README.docify.md +++ b/substrate/bin/utils/chain-spec-builder/README.docify.md @@ -26,18 +26,19 @@ _Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.i Please note that below usage is backed by integration tests. The commands' examples are wrapped around by the `bash!(...)` macro calls. - -### Deprecation notice for `CreateCmd`'s `para-id` flag +### Note for `CreateCmd`'s `para-id` flag -`para-id` flag is deprecated. Runtimes relying on generating the chain -specification with this tool should implement `cumulus_primitives_core::GetParachainInfo` -trait, a new runtime API designed to provide the parachain ID from the `parachain-info` -pallet. The `para-id` flag will be removed and nodes support for extracting the -parachain id from the chain specification will stop from `stable2512`. - -For reference, generating a chain specification with a `para_id` field can still -be done until `stable2512` like below: +Runtimes relying on generating the chain specification with this tool should +implement `cumulus_primitives_core::GetParachainInfo` trait, a new runtime API +designed to provide the parachain ID from the `parachain-info` +pallet. The `para-id` flag can be used though if the runtime does not implement +the runtime API, and the parachain id will be fetched by the node from chain +specification. This can be especially useful when syncing a node from a state +where the runtime does not implement `cumulus_primitives_core::GetParachainInfo`. + +For reference, generating a chain specification with a `para_id` field can be +done like below: ```bash chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging" diff --git a/substrate/bin/utils/chain-spec-builder/README.md b/substrate/bin/utils/chain-spec-builder/README.md index 509b0fe03bee4..31e8430776497 100644 --- a/substrate/bin/utils/chain-spec-builder/README.md +++ b/substrate/bin/utils/chain-spec-builder/README.md @@ -26,18 +26,19 @@ _Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.i Please note that below usage is backed by integration tests. The commands' examples are wrapped around by the `bash!(...)` macro calls. - -### Deprecation notice for `CreateCmd`'s `para-id` flag +### Note for `CreateCmd`'s `para-id` flag -`para-id` flag is deprecated. Runtimes relying on generating the chain -specification with this tool should implement `cumulus_primitives_core::GetParachainInfo` -trait, a new runtime API designed to provide the parachain ID from the `parachain-info` -pallet. The `para-id` flag will be removed and nodes support for extracting the -parachain id from the chain specification will stop from `stable2512`. - -For reference, generating a chain specification with a `para_id` field can still -be done until `stable2512` like below: +Runtimes relying on generating the chain specification with this tool should +implement `cumulus_primitives_core::GetParachainInfo` trait, a new runtime API +designed to provide the parachain ID from the `parachain-info` +pallet. The `para-id` flag can be used though if the runtime does not implement +the runtime API, and the parachain id will be fetched by the node from chain +specification. This can be especially useful when syncing a node from a state +where the runtime does not implement `cumulus_primitives_core::GetParachainInfo`. + +For reference, generating a chain specification with a `para_id` field can be +done like below: ```bash chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging" diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 69986aea80737..116f90d31931e 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -67,17 +67,8 @@ pub struct CreateCmd { /// The chain type. #[arg(value_enum, short = 't', default_value = "live")] chain_type: ChainType, - /// DEPRECATED: The para ID for your chain. - /// - /// This flag will be removed starting with `stable2512`. Runtimes must implement a new API - /// called `cumulus_primitives_core::GetParachainInfo` to still be compatible with node - /// versions starting with `stable2512`. - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8747 - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8740 + /// The para ID for your chain. #[arg(long, value_enum, short = 'p', requires = "relay_chain")] - #[deprecated( - note = "The para_id information is not required anymore and will be removed starting with `stable2512`. Runtimes must implement a new API called `cumulus_primitives_core::GetParachainInfo` to still be compatible with node versions starting with `stable2512`." - )] pub para_id: Option, /// The relay chain you wish to connect to. #[arg(long, value_enum, short = 'c')] @@ -226,11 +217,6 @@ pub struct ParachainExtension { /// The relay chain of the Parachain. pub relay_chain: String, /// The id of the Parachain. - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8747 --> - // TODO: https://github.com/paritytech/polkadot-sdk/issues/8740 --> - #[deprecated( - note = "The para_id information is not required anymore and will be removed starting with `stable2512`. Runtimes must implement a new API called `cumulus_primitives_core::GetParachainInfo` to still be compatible with node versions starting with `stable2512`." - )] pub para_id: Option, } @@ -458,12 +444,8 @@ pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result - eprintln!("Note: usage of deprecated `para-id` flag is not recommended. Please consider implementing the `cumulus_primitives_core::GetParachainInfo` runtime API for your runtime. The `para-id` flag will be removed starting with `stable2512`."); serde_json::json!({ "relay_chain": rc, "para_id": para_id, From 3a2eeab62c98a5c00e25b1e17da68ff3021a3e30 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 22 Aug 2025 16:18:13 +0200 Subject: [PATCH 13/16] align eth-rpc response with geth (#9177) - Update some serde encoding for eth-rpc to match serialization behavior of Geth - Add support for serializing / deserializing EIP7702 tx types - Disable transaction type we don't support yet in try_ino_unchecked_extrinsics --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- prdoc/pr_9177.prdoc | 10 + .../frame/revive/rpc/revive_chain.metadata | Bin 61568 -> 694304 bytes substrate/frame/revive/rpc/src/client.rs | 3 +- .../revive/rpc/src/client/storage_api.rs | 14 +- substrate/frame/revive/rpc/src/example.rs | 4 +- .../revive/rpc/src/fee_history_provider.rs | 4 +- .../frame/revive/rpc/src/receipt_provider.rs | 2 +- .../revive/src/evm/api/debug_rpc_types.rs | 6 +- .../frame/revive/src/evm/api/rlp_codec.rs | 73 ++++- .../frame/revive/src/evm/api/rpc_types.rs | 67 ++++ .../frame/revive/src/evm/api/rpc_types_gen.rs | 291 +++++++++++++----- .../frame/revive/src/evm/api/signature.rs | 17 + substrate/frame/revive/src/evm/api/type_id.rs | 1 + substrate/frame/revive/src/evm/runtime.rs | 17 + 14 files changed, 410 insertions(+), 99 deletions(-) create mode 100644 prdoc/pr_9177.prdoc diff --git a/prdoc/pr_9177.prdoc b/prdoc/pr_9177.prdoc new file mode 100644 index 0000000000000..9f4e954fe6048 --- /dev/null +++ b/prdoc/pr_9177.prdoc @@ -0,0 +1,10 @@ +title: align eth-rpc response with geth +doc: +- audience: Runtime Dev + description: |- + - Update serde encoding for eth-rpc to match serialization behavior of Geth +crates: +- name: pallet-revive + bump: patch +- name: pallet-revive-eth-rpc + bump: patch diff --git a/substrate/frame/revive/rpc/revive_chain.metadata b/substrate/frame/revive/rpc/revive_chain.metadata index 4c4148fa0b7cfecd729bd7365dfc7b84f44aae8e..cb98c4653acced703a2a99b134af5e373a0db154 100644 GIT binary patch literal 694304 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

o&c8YCh1AEGh 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 SubmittedTransaction { ); return Ok(receipt) } else { - anyhow::bail!("Transaction failed") + anyhow::bail!("Transaction failed receipt: {receipt:?}") } } } @@ -180,7 +180,7 @@ impl TransactionBuilder { let hash = client .send_raw_transaction(bytes.into()) .await - .with_context(|| "transaction failed")?; + .with_context(|| "send_raw_transaction failed")?; Ok(SubmittedTransaction { tx: GenericTransaction::from_signed(signed_tx, gas_price, Some(from)), diff --git a/substrate/frame/revive/rpc/src/fee_history_provider.rs b/substrate/frame/revive/rpc/src/fee_history_provider.rs index 5f4483a0453f1..3ed6f63bf7e69 100644 --- a/substrate/frame/revive/rpc/src/fee_history_provider.rs +++ b/substrate/frame/revive/rpc/src/fee_history_provider.rs @@ -47,7 +47,7 @@ impl FeeHistoryProvider { let block_number: SubstrateBlockNumber = block.number.try_into().expect("Block number is always valid"); - let base_fee = block.base_fee_per_gas.unwrap_or_default().as_u128(); + let base_fee = block.base_fee_per_gas.as_u128(); let gas_used = block.gas_used.as_u128(); let gas_used_ratio = (gas_used as f64) / (block.gas_limit.as_u128() as f64); let mut result = FeeHistoryCacheItem { base_fee, gas_used_ratio, rewards: vec![] }; @@ -160,7 +160,7 @@ impl FeeHistoryProvider { async fn test_update_fee_history() { let block = Block { number: U256::from(200u64), - base_fee_per_gas: Some(U256::from(1000u64)), + base_fee_per_gas: U256::from(1000u64), gas_used: U256::from(600u64), gas_limit: U256::from(1200u64), ..Default::default() diff --git a/substrate/frame/revive/rpc/src/receipt_provider.rs b/substrate/frame/revive/rpc/src/receipt_provider.rs index fd4c9e3854b43..01374d5763b26 100644 --- a/substrate/frame/revive/rpc/src/receipt_provider.rs +++ b/substrate/frame/revive/rpc/src/receipt_provider.rs @@ -381,7 +381,7 @@ impl ReceiptProvider { topics, transaction_hash: H256::from_slice(&transaction_hash), transaction_index: U256::from(transaction_index as u64), - removed: None, + removed: false, }) }) .fetch_all(&self.pool) diff --git a/substrate/frame/revive/src/evm/api/debug_rpc_types.rs b/substrate/frame/revive/src/evm/api/debug_rpc_types.rs index 737c0a2c4361f..7dbfc254a769a 100644 --- a/substrate/frame/revive/src/evm/api/debug_rpc_types.rs +++ b/substrate/frame/revive/src/evm/api/debug_rpc_types.rs @@ -258,13 +258,13 @@ where #[derive( TypeInfo, Default, Encode, Decode, Serialize, Deserialize, Clone, Debug, Eq, PartialEq, )] +#[serde(rename_all = "camelCase")] pub struct CallTrace { /// Address of the sender. pub from: H160, /// Amount of gas provided for the call. pub gas: Gas, /// Amount of gas used. - #[serde(rename = "gasUsed")] pub gas_used: Gas, /// Address of the receiver. pub to: H160, @@ -277,7 +277,7 @@ pub struct CallTrace { #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, /// The revert reason, if the call reverted. - #[serde(rename = "revertReason", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub revert_reason: Option, /// List of sub-calls. #[serde(skip_serializing_if = "Vec::is_empty")] @@ -313,9 +313,9 @@ pub struct CallLog { /// A transaction trace #[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] pub struct TransactionTrace { /// The transaction hash. - #[serde(rename = "txHash")] pub tx_hash: H256, /// The trace of the transaction. #[serde(rename = "result")] diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index 4094c963ac204..1ed5397de9573 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -27,6 +27,10 @@ impl TransactionUnsigned { use TransactionUnsigned::*; let mut s = rlp::RlpStream::new(); match self { + Transaction7702Unsigned(ref tx) => { + s.append(&tx.r#type.value()); + s.append(tx); + }, Transaction2930Unsigned(ref tx) => { s.append(&tx.r#type.value()); s.append(tx); @@ -54,6 +58,7 @@ impl TransactionSigned { use TransactionSigned::*; use TransactionUnsigned::*; match self { + Transaction7702Signed(tx) => Transaction7702Unsigned(tx.transaction_7702_unsigned), Transaction2930Signed(tx) => Transaction2930Unsigned(tx.transaction_2930_unsigned), Transaction1559Signed(tx) => Transaction1559Unsigned(tx.transaction_1559_unsigned), Transaction4844Signed(tx) => Transaction4844Unsigned(tx.transaction_4844_unsigned), @@ -67,6 +72,10 @@ impl TransactionSigned { use TransactionSigned::*; let mut s = rlp::RlpStream::new(); match self { + Transaction7702Signed(ref tx) => { + s.append(&tx.transaction_7702_unsigned.r#type.value()); + s.append(tx); + }, Transaction2930Signed(ref tx) => { s.append(&tx.transaction_2930_unsigned.r#type.value()); s.append(tx); @@ -198,6 +207,31 @@ impl Decodable for AccessListEntry { } } +impl Encodable for AuthorizationListEntry { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(6); + s.append(&self.chain_id); + s.append(&self.address); + s.append(&self.nonce); + s.append(&self.y_parity); + s.append(&self.r); + s.append(&self.s); + } +} + +impl Decodable for AuthorizationListEntry { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(AuthorizationListEntry { + chain_id: rlp.val_at(0)?, + address: rlp.val_at(1)?, + nonce: rlp.val_at(2)?, + y_parity: rlp.val_at(3)?, + r: rlp.val_at(4)?, + s: rlp.val_at(5)?, + }) + } +} + /// See impl Encodable for Transaction1559Unsigned { fn rlp_append(&self, s: &mut rlp::RlpStream) { @@ -344,7 +378,23 @@ impl Decodable for Transaction2930Signed { } } -//See https://eips.ethereum.org/EIPS/eip-4844 +//See https://eips.ethereum.org/EIPS/eip-7702 +impl Encodable for Transaction7702Unsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(10); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.to); + s.append(&self.value); + s.append(&self.input.0); + s.append_list(&self.access_list); + s.append_list(&self.authorization_list); + } +} + impl Encodable for Transaction4844Unsigned { fn rlp_append(&self, s: &mut rlp::RlpStream) { s.begin_list(11); @@ -362,6 +412,27 @@ impl Encodable for Transaction4844Unsigned { } } +//See https://eips.ethereum.org/EIPS/eip-7702 +impl Encodable for Transaction7702Signed { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + let tx = &self.transaction_7702_unsigned; + s.begin_list(13); + s.append(&tx.chain_id); + s.append(&tx.nonce); + s.append(&tx.max_priority_fee_per_gas); + s.append(&tx.max_fee_per_gas); + s.append(&tx.gas); + s.append(&tx.to); + s.append(&tx.value); + s.append(&tx.input.0); + s.append_list(&tx.access_list); + s.append_list(&tx.authorization_list); + s.append(&self.y_parity); + s.append(&self.r); + s.append(&self.s); + } +} + //See https://eips.ethereum.org/EIPS/eip-4844 impl Encodable for Transaction4844Signed { fn rlp_append(&self, s: &mut rlp::RlpStream) { diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs index 195c1c5fd4623..09b9f67271504 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -32,6 +32,7 @@ impl From for TransactionUnsigned { fn from(tx: TransactionSigned) -> Self { use TransactionSigned::*; match tx { + Transaction7702Signed(tx) => tx.transaction_7702_unsigned.into(), Transaction4844Signed(tx) => tx.transaction_4844_unsigned.into(), Transaction1559Signed(tx) => tx.transaction_1559_unsigned.into(), Transaction2930Signed(tx) => tx.transaction_2930_unsigned.into(), @@ -281,6 +282,26 @@ impl GenericTransaction { access_list: Some(tx.access_list), ..Default::default() }, + Transaction7702Unsigned(tx) => GenericTransaction { + from, + r#type: Some(tx.r#type.as_byte()), + chain_id: Some(tx.chain_id), + input: tx.input.into(), + nonce: Some(tx.nonce), + value: Some(tx.value), + to: tx.to, + gas: Some(tx.gas), + gas_price: Some( + base_gas_price + .saturating_add(tx.max_priority_fee_per_gas) + .min(tx.max_fee_per_gas), + ), + access_list: Some(tx.access_list), + authorization_list: tx.authorization_list, + max_fee_per_gas: Some(tx.max_fee_per_gas), + max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas), + ..Default::default() + }, } } @@ -339,6 +360,21 @@ impl GenericTransaction { blob_versioned_hashes: self.blob_versioned_hashes, } .into()), + TYPE_EIP7702 => Ok(Transaction7702Unsigned { + r#type: TypeEip7702 {}, + chain_id: self.chain_id.unwrap_or_default(), + input: self.input.to_bytes(), + nonce: self.nonce.unwrap_or_default(), + value: self.value.unwrap_or_default(), + to: self.to, + gas: self.gas.unwrap_or_default(), + gas_price: self.max_fee_per_gas.unwrap_or_default(), + max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(), + max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(), + access_list: self.access_list.unwrap_or_default(), + authorization_list: self.authorization_list, + } + .into()), _ => Err(()), } } @@ -387,3 +423,34 @@ fn from_unsigned_works_for_1559() { let tx2 = generic.try_into_unsigned().unwrap(); assert_eq!(tx, tx2); } + +#[test] +fn from_unsigned_works_for_7702() { + let base_gas_price = U256::from(10); + let tx = TransactionUnsigned::from(Transaction7702Unsigned { + chain_id: U256::from(1), + input: Bytes::from(vec![1u8]), + nonce: U256::from(1), + value: U256::from(1), + to: Some(H160::zero()), + gas: U256::from(1), + gas_price: U256::from(20), + max_fee_per_gas: U256::from(20), + max_priority_fee_per_gas: U256::from(1), + authorization_list: vec![AuthorizationListEntry { + chain_id: U256::from(1), + address: H160::from_low_u64_be(42), + nonce: U256::from(0), + y_parity: U256::from(1), + r: U256::from(1), + s: U256::from(2), + }], + ..Default::default() + }); + + let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None); + assert_eq!(generic.gas_price, Some(U256::from(11))); + + let tx2 = generic.try_into_unsigned().unwrap(); + assert_eq!(tx, tx2); +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs index 549dde9dea954..7ca087ff53fe4 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -17,7 +17,7 @@ //! Generated JSON-RPC types. #![allow(missing_docs)] -use super::{byte::*, TypeEip1559, TypeEip2930, TypeEip4844, TypeLegacy}; +use super::{byte::*, TypeEip1559, TypeEip2930, TypeEip4844, TypeEip7702, TypeLegacy}; use alloc::vec::Vec; use codec::{Decode, Encode}; use derive_more::{From, TryInto}; @@ -75,76 +75,64 @@ fn deserialize_input_or_data<'d, D: Deserializer<'d>>(d: D) -> Result, + pub base_fee_per_gas: U256, /// Blob gas used - #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] - pub blob_gas_used: Option, + pub blob_gas_used: U256, /// Difficulty - #[serde(skip_serializing_if = "Option::is_none")] - pub difficulty: Option, + pub difficulty: U256, /// Excess blob gas - #[serde(rename = "excessBlobGas", skip_serializing_if = "Option::is_none")] - pub excess_blob_gas: Option, + pub excess_blob_gas: U256, /// Extra data - #[serde(rename = "extraData")] pub extra_data: Bytes, /// Gas limit - #[serde(rename = "gasLimit")] pub gas_limit: U256, /// Gas used - #[serde(rename = "gasUsed")] pub gas_used: U256, /// Hash pub hash: H256, /// Bloom filter - #[serde(rename = "logsBloom")] pub logs_bloom: Bytes256, /// Coinbase pub miner: Address, /// Mix hash - #[serde(rename = "mixHash")] pub mix_hash: H256, /// Nonce pub nonce: Bytes8, /// Number pub number: U256, /// Parent Beacon Block Root - #[serde(rename = "parentBeaconBlockRoot", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub parent_beacon_block_root: Option, /// Parent block hash - #[serde(rename = "parentHash")] pub parent_hash: H256, /// Receipts root - #[serde(rename = "receiptsRoot")] pub receipts_root: H256, + /// Requests root + #[serde(skip_serializing_if = "Option::is_none")] + pub requests_hash: Option, /// Ommers hash - #[serde(rename = "sha3Uncles")] pub sha_3_uncles: H256, /// Block size pub size: U256, /// State root - #[serde(rename = "stateRoot")] pub state_root: H256, /// Timestamp pub timestamp: U256, /// Total difficulty - #[serde(rename = "totalDifficulty", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub total_difficulty: Option, pub transactions: HashesOrTransactionInfos, /// Transactions root - #[serde(rename = "transactionsRoot")] pub transactions_root: H256, /// Uncles pub uncles: Vec, /// Withdrawals - #[serde(default, skip_serializing_if = "Vec::is_empty")] pub withdrawals: Vec, /// Withdrawals root - #[serde(rename = "withdrawalsRoot", skip_serializing_if = "Option::is_none")] - pub withdrawals_root: Option, + pub withdrawals_root: H256, } /// Block number or tag @@ -221,17 +209,18 @@ impl<'a> serde::Deserialize<'a> for BlockNumberOrTagOrHash { /// filter #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Filter { /// Address(es) pub address: Option, /// from block - #[serde(rename = "fromBlock", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub from_block: Option, /// to block - #[serde(rename = "toBlock", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub to_block: Option, /// Restricts the logs returned to the single block - #[serde(rename = "blockHash", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub block_hash: Option, /// Topics #[serde(skip_serializing_if = "Option::is_none")] @@ -257,14 +246,19 @@ impl Default for FilterResults { #[derive( Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, )] +#[serde(rename_all = "camelCase")] pub struct GenericTransaction { /// accessList /// EIP-2930 access list - #[serde(rename = "accessList", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub access_list: Option, + /// authorizationList + /// List of account code authorizations (EIP-7702) + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub authorization_list: Vec, /// blobVersionedHashes /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. - #[serde(rename = "blobVersionedHashes", default, skip_serializing_if = "Vec::is_empty")] + #[serde(default)] pub blob_versioned_hashes: Vec, /// blobs /// Raw blob data. @@ -272,7 +266,7 @@ pub struct GenericTransaction { pub blobs: Vec, /// chainId /// Chain ID that this transaction is valid on. - #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub chain_id: Option, /// from address #[serde(skip_serializing_if = "Option::is_none")] @@ -282,23 +276,23 @@ pub struct GenericTransaction { pub gas: Option, /// gas price /// The gas price willing to be paid by the sender in wei - #[serde(rename = "gasPrice", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub gas_price: Option, /// input data #[serde(flatten, deserialize_with = "deserialize_input_or_data")] pub input: InputOrData, /// max fee per blob gas /// The maximum total fee per gas the sender is willing to pay for blob gas in wei - #[serde(rename = "maxFeePerBlobGas", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub max_fee_per_blob_gas: Option, /// max fee per gas /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee /// and miner / priority fee) in wei - #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub max_fee_per_gas: Option, /// max priority fee per gas /// Maximum fee per gas the sender is willing to pay to miners in wei - #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub max_priority_fee_per_gas: Option, /// nonce #[serde(skip_serializing_if = "Option::is_none")] @@ -315,47 +309,41 @@ pub struct GenericTransaction { /// Receipt information #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct ReceiptInfo { /// blob gas price /// The actual value per gas deducted from the sender's account for blob gas. Only specified /// for blob transactions as defined by EIP-4844. - #[serde(rename = "blobGasPrice", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub blob_gas_price: Option, /// blob gas used /// The amount of blob gas used for this specific transaction. Only specified for blob /// transactions as defined by EIP-4844. - #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub blob_gas_used: Option, /// block hash - #[serde(rename = "blockHash")] pub block_hash: H256, /// block number - #[serde(rename = "blockNumber")] pub block_number: U256, /// contract address /// The contract address created, if the transaction was a contract creation, otherwise null. - #[serde(rename = "contractAddress")] pub contract_address: Option

, /// cumulative gas used /// The sum of gas used by this transaction and all preceding transactions in the same block. - #[serde(rename = "cumulativeGasUsed")] pub cumulative_gas_used: U256, /// effective gas price /// The actual value per gas deducted from the sender's account. Before EIP-1559, this is equal /// to the transaction's gas price. After, it is equal to baseFeePerGas + min(maxFeePerGas - /// baseFeePerGas, maxPriorityFeePerGas). - #[serde(rename = "effectiveGasPrice")] pub effective_gas_price: U256, /// from pub from: Address, /// gas used /// The amount of gas used for this specific transaction alone. - #[serde(rename = "gasUsed")] pub gas_used: U256, /// logs pub logs: Vec, /// logs bloom - #[serde(rename = "logsBloom")] pub logs_bloom: Bytes256, /// state root /// The post-transaction state root. Only specified for transactions included before the @@ -371,10 +359,8 @@ pub struct ReceiptInfo { /// Address of the receiver or null in a contract creation transaction. pub to: Option
, /// transaction hash - #[serde(rename = "transactionHash")] pub transaction_hash: H256, /// transaction index - #[serde(rename = "transactionIndex")] pub transaction_index: U256, /// type #[serde(skip_serializing_if = "Option::is_none")] @@ -399,19 +385,17 @@ impl Default for SyncingStatus { /// Transaction information #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct TransactionInfo { /// block hash - #[serde(rename = "blockHash")] pub block_hash: H256, /// block number - #[serde(rename = "blockNumber")] pub block_number: U256, /// from address pub from: Address, /// transaction hash pub hash: H256, /// transaction index - #[serde(rename = "transactionIndex")] pub transaction_index: U256, #[serde(flatten)] pub transaction_signed: TransactionSigned, @@ -420,6 +404,7 @@ pub struct TransactionInfo { #[derive(Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] #[serde(untagged)] pub enum TransactionUnsigned { + Transaction7702Unsigned(Transaction7702Unsigned), Transaction4844Unsigned(Transaction4844Unsigned), Transaction1559Unsigned(Transaction1559Unsigned), Transaction2930Unsigned(Transaction2930Unsigned), @@ -463,17 +448,13 @@ pub type Addresses = Vec
; /// transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to /// with `-39001: Unknown block` error #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "lowercase")] pub enum BlockTag { - #[serde(rename = "earliest")] Earliest, - #[serde(rename = "finalized")] Finalized, - #[serde(rename = "safe")] Safe, - #[serde(rename = "latest")] #[default] Latest, - #[serde(rename = "pending")] Pending, } @@ -496,59 +477,55 @@ impl Default for HashesOrTransactionInfos { /// log #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Log { /// address pub address: Address, /// block hash - #[serde(rename = "blockHash")] pub block_hash: H256, /// block number - #[serde(rename = "blockNumber")] pub block_number: U256, /// data #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, /// log index - #[serde(rename = "logIndex")] pub log_index: U256, /// removed - #[serde(skip_serializing_if = "Option::is_none")] - pub removed: Option, + #[serde(default)] + pub removed: bool, /// topics - #[serde(default, skip_serializing_if = "Vec::is_empty")] + #[serde(default)] pub topics: Vec, /// transaction hash - #[serde(rename = "transactionHash")] pub transaction_hash: H256, /// transaction index - #[serde(rename = "transactionIndex")] pub transaction_index: U256, } /// Syncing progress #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct SyncingProgress { /// Current block - #[serde(rename = "currentBlock", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub current_block: Option, /// Highest block - #[serde(rename = "highestBlock", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub highest_block: Option, /// Starting block - #[serde(rename = "startingBlock", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub starting_block: Option, } /// EIP-1559 transaction. #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction1559Unsigned { /// accessList /// EIP-2930 access list - #[serde(rename = "accessList")] pub access_list: AccessList, /// chainId /// Chain ID that this transaction is valid on. - #[serde(rename = "chainId")] pub chain_id: U256, /// gas limit pub gas: U256, @@ -556,18 +533,15 @@ pub struct Transaction1559Unsigned { /// The effective gas price paid by the sender in wei. For transactions not yet included in a /// block, this value should be set equal to the max fee per gas. This field is DEPRECATED, /// please transition to using effectiveGasPrice in the receipt object going forward. - #[serde(rename = "gasPrice")] pub gas_price: U256, /// input data pub input: Bytes, /// max fee per gas /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee /// and miner / priority fee) in wei - #[serde(rename = "maxFeePerGas")] pub max_fee_per_gas: U256, /// max priority fee per gas /// Maximum fee per gas the sender is willing to pay to miners in wei - #[serde(rename = "maxPriorityFeePerGas")] pub max_priority_fee_per_gas: U256, /// nonce pub nonce: U256, @@ -581,20 +555,18 @@ pub struct Transaction1559Unsigned { /// EIP-2930 transaction. #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction2930Unsigned { /// accessList /// EIP-2930 access list - #[serde(rename = "accessList")] pub access_list: AccessList, /// chainId /// Chain ID that this transaction is valid on. - #[serde(rename = "chainId")] pub chain_id: U256, /// gas limit pub gas: U256, /// gas price /// The gas price willing to be paid by the sender in wei - #[serde(rename = "gasPrice")] pub gas_price: U256, /// input data pub input: Bytes, @@ -610,18 +582,16 @@ pub struct Transaction2930Unsigned { /// EIP-4844 transaction. #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction4844Unsigned { /// accessList /// EIP-2930 access list - #[serde(rename = "accessList")] pub access_list: AccessList, /// blobVersionedHashes /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. - #[serde(rename = "blobVersionedHashes")] pub blob_versioned_hashes: Vec, /// chainId /// Chain ID that this transaction is valid on. - #[serde(rename = "chainId")] pub chain_id: U256, /// gas limit pub gas: U256, @@ -629,16 +599,13 @@ pub struct Transaction4844Unsigned { pub input: Bytes, /// max fee per blob gas /// The maximum total fee per gas the sender is willing to pay for blob gas in wei - #[serde(rename = "maxFeePerBlobGas")] pub max_fee_per_blob_gas: U256, /// max fee per gas /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee /// and miner / priority fee) in wei - #[serde(rename = "maxFeePerGas")] pub max_fee_per_gas: U256, /// max priority fee per gas /// Maximum fee per gas the sender is willing to pay to miners in wei - #[serde(rename = "maxPriorityFeePerGas")] pub max_priority_fee_per_gas: U256, /// nonce pub nonce: U256, @@ -652,16 +619,16 @@ pub struct Transaction4844Unsigned { /// Legacy transaction. #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct TransactionLegacyUnsigned { /// chainId /// Chain ID that this transaction is valid on. - #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub chain_id: Option, /// gas limit pub gas: U256, /// gas price /// The gas price willing to be paid by the sender in wei - #[serde(rename = "gasPrice")] pub gas_price: U256, /// input data pub input: Bytes, @@ -675,9 +642,71 @@ pub struct TransactionLegacyUnsigned { pub value: U256, } +/// EIP-7702 transaction. +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] +#[serde(rename_all = "camelCase")] +pub struct Transaction7702Unsigned { + /// accessList + /// EIP-2930 access list + pub access_list: AccessList, + /// authorizationList + /// List of account code authorizations + pub authorization_list: Vec, + /// chainId + /// Chain ID that this transaction is valid on. + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// gas price + /// The effective gas price paid by the sender in wei. For transactions not yet included in a + /// block, this value should be set equal to the max fee per gas. This field is DEPRECATED, + /// please transition to using effectiveGasPrice in the receipt object going forward. + pub gas_price: U256, + /// input data + pub input: Bytes, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + pub max_fee_per_gas: U256, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + pub max_priority_fee_per_gas: U256, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: TypeEip7702, + /// value + pub value: U256, +} + +/// Authorization list entry for EIP-7702 +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] +#[serde(rename_all = "camelCase")] +pub struct AuthorizationListEntry { + /// Chain ID that this authorization is valid on + pub chain_id: U256, + /// Address to authorize + pub address: Address, + /// Nonce of the authorization + pub nonce: U256, + /// y-parity of the signature + pub y_parity: U256, + /// r component of signature + pub r: U256, + /// s component of signature + pub s: U256, +} + #[derive(Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] #[serde(untagged)] pub enum TransactionSigned { + Transaction7702Signed(Transaction7702Signed), Transaction4844Signed(Transaction4844Signed), Transaction1559Signed(Transaction1559Signed), Transaction2930Signed(Transaction2930Signed), @@ -689,8 +718,29 @@ impl Default for TransactionSigned { } } +impl TransactionSigned { + /// Get the effective gas price. + pub fn effective_gas_price(&self, base_gas_price: U256) -> U256 { + match &self { + TransactionSigned::TransactionLegacySigned(tx) => + tx.transaction_legacy_unsigned.gas_price, + TransactionSigned::Transaction7702Signed(tx) => base_gas_price + .saturating_add(tx.transaction_7702_unsigned.max_priority_fee_per_gas) + .min(tx.transaction_7702_unsigned.max_fee_per_gas), + TransactionSigned::Transaction4844Signed(tx) => base_gas_price + .saturating_add(tx.transaction_4844_unsigned.max_priority_fee_per_gas) + .min(tx.transaction_4844_unsigned.max_fee_per_blob_gas), + TransactionSigned::Transaction1559Signed(tx) => base_gas_price + .saturating_add(tx.transaction_1559_unsigned.max_priority_fee_per_gas) + .min(tx.transaction_1559_unsigned.max_fee_per_gas), + TransactionSigned::Transaction2930Signed(tx) => tx.transaction_2930_unsigned.gas_price, + } + } +} + /// Validator withdrawal #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Withdrawal { /// recipient address for withdrawal value pub address: Address, @@ -699,7 +749,6 @@ pub struct Withdrawal { /// index of withdrawal pub index: U256, /// index of validator that generated withdrawal - #[serde(rename = "validatorIndex")] pub validator_index: U256, } @@ -707,9 +756,9 @@ pub struct Withdrawal { #[derive( Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, )] +#[serde(rename_all = "camelCase")] pub struct AccessListEntry { pub address: Address, - #[serde(rename = "storageKeys")] pub storage_keys: Vec, } @@ -728,8 +777,31 @@ impl Default for FilterTopic { } } +/// Signed 7702 Transaction +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] +#[serde(rename_all = "camelCase")] +pub struct Transaction7702Signed { + #[serde(flatten)] + pub transaction_7702_unsigned: Transaction7702Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + /// For backwards compatibility, `v` is optionally provided as an alternative to `yParity`. + /// This field is DEPRECATED and all use of it should migrate to `yParity`. + #[serde(skip_serializing_if = "Option::is_none")] + pub v: Option, + /// yParity + /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. + pub y_parity: U256, +} + /// Signed 1559 Transaction #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction1559Signed { #[serde(flatten)] pub transaction_1559_unsigned: Transaction1559Unsigned, @@ -744,12 +816,12 @@ pub struct Transaction1559Signed { pub v: Option, /// yParity /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. - #[serde(rename = "yParity")] pub y_parity: U256, } /// Signed 2930 Transaction #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction2930Signed { #[serde(flatten)] pub transaction_2930_unsigned: Transaction2930Unsigned, @@ -764,12 +836,12 @@ pub struct Transaction2930Signed { pub v: Option, /// yParity /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. - #[serde(rename = "yParity")] pub y_parity: U256, } /// Signed 4844 Transaction #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Transaction4844Signed { #[serde(flatten)] pub transaction_4844_unsigned: Transaction4844Unsigned, @@ -779,7 +851,6 @@ pub struct Transaction4844Signed { pub s: U256, /// yParity /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. - #[serde(rename = "yParity")] pub y_parity: U256, } @@ -821,3 +892,53 @@ pub struct FeeHistoryResult { #[serde(default, skip_serializing_if = "Vec::is_empty")] pub reward: Vec>, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_block_serialization_roundtrip() { + let json_input = r#"{ + "baseFeePerGas": "0x126f2347", + "blobGasUsed": "0x100000", + "difficulty": "0x0", + "excessBlobGas": "0x0", + "extraData": "0x546974616e2028746974616e6275696c6465722e78797a29", + "gasLimit": "0x2aca2c9", + "gasUsed": "0x1c06043", + "hash": "0xe6064637def8a5a9a90c8a666005975e4a6c46acf8af57e1f2adb20dfced133a", + "logsBloom": "0xbf7bf1afcf57ea95fbb5c6fd8db37db9dbffec27cfc6a39b3417e7786defd7e3d6fd577ecddd5676eee8bf79df8faddcefa7e169def77f7e7d6dbbfd1dfef9aebd9e707b4c4ed979fda2cdeeb96b3bfed5d5fabb68ff9e7f2dfb075eff643a93feebbc07877f0dff66fedf4ede0fbcfbf56f98a1626eaed77ed4e6be388f162f9b2deeff1eefa93bdacbf3fbbd7b6757cddb7ae5b3f9b7af9c3bbff7e7f6ddef9f2dff7f17997ea6867675c29fcbe6bf725efbffe1507589bfd47a3bf7b6f5dfde50776fd94fe772d2c7b6b58baf554de55c176f27efa6fdcff7f17689bafa7f7c7bf4fd5fb9b05c2f4ed785f17ac9779feeaf1f5bbdadfc42ebad367fdcf7ad", + "miner": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97", + "mixHash": "0x7e53d2d6772895d024eb00da80213aec81fb4a15bec34a5a39403ad6162274af", + "nonce": "0x0000000000000000", + "number": "0x1606672", + "parentBeaconBlockRoot": "0xd9ef51c8f4155f238ba66df0d35a4d0a6bb043c0dacb5c5dbd5a231bbd4c8a01", + "parentHash": "0x37b527c98c86436f292d4e19fac3aba6d8c7768684ea972f50adc305fd9a1475", + "receiptsRoot": "0x2abab67c41b350435eb34f9dc0478dd7d262f35544cecf62a85af2da075bd38d", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x29e6c", + "stateRoot": "0x5159c56472adff9a760275ac63524a71f5645ede822a5547dd9ad333586d5157", + "timestamp": "0x6895a93f", + "transactions": [], + "transactionsRoot": "0xfb0b9f5b28bc927db98d82e18070d2b17434c31bd2773c5dd699e96fa76a34cd", + "uncles": [], + "withdrawals": [], + "withdrawalsRoot": "0x531480435633d56a52433b33f41ac9322f51a2df3364c4c112236fc6ac583118" + }"#; + + // Deserialize the JSON into a Block + let block: Block = serde_json::from_str(json_input).expect("Failed to deserialize block"); + + // Serialize it back to JSON + let serialized = serde_json::to_string(&block).expect("Failed to serialize block"); + + // Deserialize again to ensure roundtrip consistency + let block_roundtrip: Block = + serde_json::from_str(&serialized).expect("Failed to deserialize roundtrip block"); + + // Verify that deserializing and serializing leads to the same result + assert_eq!(block, block_roundtrip); + } +} diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index de4ac428ffe4e..21cb943385b6a 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -42,6 +42,8 @@ impl TransactionUnsigned { match tx { TransactionSigned::TransactionLegacySigned(signed) => Self::TransactionLegacyUnsigned(signed.transaction_legacy_unsigned), + TransactionSigned::Transaction7702Signed(signed) => + Self::Transaction7702Unsigned(signed.transaction_7702_unsigned), TransactionSigned::Transaction4844Signed(signed) => Self::Transaction4844Unsigned(signed.transaction_4844_unsigned), TransactionSigned::Transaction1559Signed(signed) => @@ -58,6 +60,15 @@ impl TransactionUnsigned { let recovery_id = signature[64]; match self { + TransactionUnsigned::Transaction7702Unsigned(transaction_7702_unsigned) => + Transaction7702Signed { + transaction_7702_unsigned, + r, + s, + v: None, + y_parity: U256::from(recovery_id), + } + .into(), TransactionUnsigned::Transaction2930Unsigned(transaction_2930_unsigned) => Transaction2930Signed { transaction_2930_unsigned, @@ -108,6 +119,7 @@ impl TransactionSigned { use TransactionSigned::*; let (r, s, v) = match self { TransactionLegacySigned(tx) => (tx.r, tx.s, tx.extract_recovery_id().ok_or(())?), + Transaction7702Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), Transaction4844Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), Transaction1559Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), Transaction2930Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), @@ -129,6 +141,11 @@ impl TransactionSigned { let tx = &tx.transaction_legacy_unsigned; s.append(tx); }, + Transaction7702Signed(tx) => { + let tx = &tx.transaction_7702_unsigned; + s.append(&tx.r#type.value()); + s.append(tx); + }, Transaction4844Signed(tx) => { let tx = &tx.transaction_4844_unsigned; s.append(&tx.r#type.value()); diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs index c6e018a379b37..81cf44d857625 100644 --- a/substrate/frame/revive/src/evm/api/type_id.rs +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -118,6 +118,7 @@ transaction_type!(TypeLegacy, 0); transaction_type!(TypeEip2930, 1); transaction_type!(TypeEip1559, 2); transaction_type!(TypeEip4844, 3); +transaction_type!(TypeEip7702, 4); #[test] fn transaction_type() { diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 48380f83899bd..5aed60859485c 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -294,6 +294,23 @@ pub trait EthExtra { InvalidTransaction::Call })?; + // Check transaction type and reject unsupported transaction types + match &tx { + crate::evm::api::TransactionSigned::Transaction1559Signed(_) | + crate::evm::api::TransactionSigned::Transaction2930Signed(_) | + crate::evm::api::TransactionSigned::TransactionLegacySigned(_) => { + // Supported transaction types, continue processing + }, + crate::evm::api::TransactionSigned::Transaction7702Signed(_) => { + log::debug!(target: LOG_TARGET, "EIP-7702 transactions are not supported"); + return Err(InvalidTransaction::Call); + }, + crate::evm::api::TransactionSigned::Transaction4844Signed(_) => { + log::debug!(target: LOG_TARGET, "EIP-4844 transactions are not supported"); + return Err(InvalidTransaction::Call); + }, + } + let signer_addr = tx.recover_eth_address().map_err(|err| { log::debug!(target: LOG_TARGET, "Failed to recover signer: {err:?}"); InvalidTransaction::BadProof From f95460315bc300f303669c7f7e7fee8c1a17bce5 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 25 Aug 2025 10:57:56 +0300 Subject: [PATCH 14/16] [XCMP] `take_first_concatenated_xcm()` improvements (#9539) This PR: - improves `take_first_concatenated_xcm()` avoiding the XCM re-encoding - makes the benchmarks for `take_first_concatenated_xcm()` more granular, accounting for the number of bytes of the message --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../pallets/xcmp-queue/src/benchmarking.rs | 40 ++--- cumulus/pallets/xcmp-queue/src/lib.rs | 62 ++++--- cumulus/pallets/xcmp-queue/src/tests.rs | 16 +- cumulus/pallets/xcmp-queue/src/weights.rs | 166 +++++++++--------- .../src/weights/cumulus_pallet_xcmp_queue.rs | 69 ++++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 97 +++++----- .../src/weights/cumulus_pallet_xcmp_queue.rs | 67 +++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 67 +++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 89 +++++----- .../src/weights/cumulus_pallet_xcmp_queue.rs | 65 +++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 65 +++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 67 +++---- .../src/weights/cumulus_pallet_xcmp_queue.rs | 67 +++---- prdoc/pr_9539.prdoc | 28 +++ .../src/weights/cumulus_pallet_xcmp_queue.rs | 9 +- 15 files changed, 521 insertions(+), 453 deletions(-) create mode 100644 prdoc/pr_9539.prdoc diff --git a/cumulus/pallets/xcmp-queue/src/benchmarking.rs b/cumulus/pallets/xcmp-queue/src/benchmarking.rs index 55916c5513b57..cc6ff9c87b5ea 100644 --- a/cumulus/pallets/xcmp-queue/src/benchmarking.rs +++ b/cumulus/pallets/xcmp-queue/src/benchmarking.rs @@ -59,7 +59,7 @@ mod benchmarks { { assert_ok!(Pallet::::enqueue_xcmp_messages( 0.into(), - &[msg], + &[msg.as_bounded_slice()], &mut WeightMeter::new() )); } @@ -86,7 +86,8 @@ mod benchmarks { }); } - let msgs = vec![Default::default(); n as usize]; + let msg = BoundedVec::new(); + let msgs = vec![msg.as_bounded_slice(); n as usize]; #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); @@ -120,7 +121,7 @@ mod benchmarks { assert_ok!(Pallet::::enqueue_xcmp_messages( 0.into(), - &[BoundedVec::try_from(vec![0; n as usize]).unwrap()], + &[BoundedVec::try_from(vec![0; n as usize]).unwrap().as_bounded_slice()], &mut WeightMeter::new() )); @@ -130,7 +131,7 @@ mod benchmarks { { assert_ok!(Pallet::::enqueue_xcmp_messages( 0.into(), - &[Default::default()], + &[BoundedVec::new().as_bounded_slice()], &mut WeightMeter::new() )); } @@ -169,7 +170,7 @@ mod benchmarks { { assert_ok!(Pallet::::enqueue_xcmp_messages( 0.into(), - &msgs, + &msgs.iter().map(|msg| msg.as_bounded_slice()).collect::>(), &mut WeightMeter::new() )); } @@ -198,7 +199,8 @@ mod benchmarks { get_average_page_pos(MaxXcmpMessageLenOf::::get()) as usize ]) - .unwrap()], + .unwrap() + .as_bounded_slice()], &mut WeightMeter::new() )); @@ -213,7 +215,7 @@ mod benchmarks { { assert_ok!(Pallet::::enqueue_xcmp_messages( 0.into(), - &msgs, + &msgs.iter().map(|msg| msg.as_bounded_slice()).collect::>(), &mut WeightMeter::new() )); } @@ -266,30 +268,14 @@ mod benchmarks { /// Split a singular XCM. #[benchmark] - fn take_first_concatenated_xcm() { - let max_message_size = MaxXcmpMessageLenOf::::get() as usize; - - assert!(MAX_INSTRUCTIONS_TO_DECODE as u32 > MAX_XCM_DECODE_DEPTH, "Preconditon failed"); - let max_instrs = MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH; - let mut xcm = Xcm::(vec![ClearOrigin; max_instrs as usize]); - + fn take_first_concatenated_xcm( + n: Linear<0, { MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH }>, + ) { + let mut xcm = Xcm::(vec![ClearOrigin; n as usize]); for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { xcm = Xcm::(vec![Instruction::SetAppendix(xcm)]); } - let data = VersionedXcm::::from(xcm).encode(); - assert!(data.len() < max_message_size, "Page size is too small"); - // Verify that decoding works with the exact recursion limit: - VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut &data[..], - ) - .unwrap(); - VersionedXcm::::decode_all_with_depth_limit( - MAX_XCM_DECODE_DEPTH - 1, - &mut &data[..], - ) - .unwrap_err(); #[block] { diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 5d2ad6c15c895..1f144aa051645 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -56,7 +56,7 @@ pub use weights_ext::WeightInfoExt; extern crate alloc; use alloc::{collections::BTreeSet, vec, vec::Vec}; -use bounded_collections::BoundedBTreeSet; +use bounded_collections::{BoundedBTreeSet, BoundedSlice, BoundedVec}; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError, @@ -70,7 +70,6 @@ use frame_support::{ QueuePausedQuery, }, weights::{Weight, WeightMeter}, - BoundedVec, }; use pallet_message_queue::OnQueueChanged; use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery; @@ -641,17 +640,14 @@ impl Pallet { }); } - fn enqueue_xcmp_messages( + fn enqueue_xcmp_messages<'a>( sender: ParaId, - xcms: &[BoundedVec>], + xcms: &[BoundedSlice<'a, u8, MaxXcmpMessageLenOf>], meter: &mut WeightMeter, ) -> Result<(), ()> { let QueueConfigData { drop_threshold, .. } = >::get(); - let batches_footprints = T::XcmpQueue::get_batches_footprints( - sender, - xcms.iter().map(|xcm| xcm.as_bounded_slice()), - drop_threshold, - ); + let batches_footprints = + T::XcmpQueue::get_batches_footprints(sender, xcms.iter().copied(), drop_threshold); let best_batch_footprint = batches_footprints.search_best_by(|batch_info| { let required_weight = T::WeightInfo::enqueue_xcmp_messages( @@ -670,9 +666,7 @@ impl Pallet { best_batch_footprint, )); T::XcmpQueue::enqueue_messages( - xcms.iter() - .take(best_batch_footprint.msgs_count) - .map(|xcm| xcm.as_bounded_slice()), + xcms.iter().take(best_batch_footprint.msgs_count).copied(), sender, ); @@ -695,42 +689,62 @@ impl Pallet { /// /// On error returns a partial batch with all the XCMs processed before the failure. /// This can happen in case of a decoding/re-encoding failure. - pub(crate) fn take_first_concatenated_xcm( - data: &mut &[u8], + pub(crate) fn take_first_concatenated_xcm<'a>( + data: &mut &'a [u8], meter: &mut WeightMeter, - ) -> Result>>, ()> { + ) -> Result>>, ()> { if data.is_empty() { return Ok(None) } - if meter.try_consume(T::WeightInfo::take_first_concatenated_xcm()).is_err() { + // Let's make sure that we can decode at least an empty xcm message. + let base_weight = T::WeightInfo::take_first_concatenated_xcm(0); + if meter.try_consume(base_weight).is_err() { defensive!("Out of weight; could not decode all; dropping"); return Err(()) } - let xcm = VersionedXcm::<()>::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, data).map_err( + let input_data = &mut &data[..]; + let mut input = codec::CountedInput::new(input_data); + VersionedXcm::<()>::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut input).map_err( |error| { tracing::debug!(target: LOG_TARGET, ?error, "Failed to decode XCM with depth limit"); () }, )?; - Ok(Some(xcm.encode().try_into().map_err(|error| { - tracing::debug!(target: LOG_TARGET, ?error, "Failed to encode XCM after decoding"); + let (xcm_data, remaining_data) = data.split_at(input.count() as usize); + *data = remaining_data; + + // Consume the extra weight that it took to decode this message. + // This depends on the message len in bytes. + // Saturates if it's over the limit. + let extra_weight = + T::WeightInfo::take_first_concatenated_xcm(xcm_data.len() as u32) - base_weight; + meter.consume(extra_weight); + + let xcm = Some(BoundedSlice::try_from(xcm_data).map_err(|error| { + tracing::error!( + target: LOG_TARGET, + ?error, + "Failed to take XCM after decoding: message is too long" + ); () - })?)) + })?); + + Ok(xcm) } /// Split concatenated encoded `VersionedXcm`s or `MaybeDoubleEncodedVersionedXcm`s into /// batches. /// /// We directly encode them again since that is needed later on. - pub(crate) fn take_first_concatenated_xcms( - data: &mut &[u8], + pub(crate) fn take_first_concatenated_xcms<'a>( + data: &mut &'a [u8], batch_size: usize, meter: &mut WeightMeter, ) -> Result< - Vec>>, - Vec>>, + Vec>>, + Vec>>, > { let mut batch = vec![]; loop { diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index cefbe401df1d7..fbaacc9e682c3 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -220,7 +220,11 @@ fn xcm_enqueueing_starts_dropping_on_out_of_weight() { ); let mut weight_meter = WeightMeter::with_limit(required_weight); - let res = XcmpQueue::enqueue_xcmp_messages(1000.into(), &xcms, &mut weight_meter); + let res = XcmpQueue::enqueue_xcmp_messages( + 1000.into(), + &xcms.iter().map(|xcm| xcm.as_bounded_slice()).collect::>(), + &mut weight_meter, + ); if idx < xcms.len() - 1 { assert!(res.is_err()); } else { @@ -709,10 +713,10 @@ fn take_first_concatenated_xcm_works() { .unwrap(); match i % 2 { 0 => { - assert_eq!(xcm, versioned_xcm(older_xcm_version).encode()); + assert_eq!(xcm.to_vec(), versioned_xcm(older_xcm_version).encode()); }, 1 => { - assert_eq!(xcm, versioned_xcm(newer_xcm_version).encode()); + assert_eq!(xcm.to_vec(), versioned_xcm(newer_xcm_version).encode()); }, unexpected => unreachable!("{:?}", unexpected), } @@ -756,11 +760,11 @@ fn take_first_concatenated_xcms_works() { let data = &mut &page[1..]; assert_eq!( XcmpQueue::take_first_concatenated_xcms(data, 5, &mut WeightMeter::new()), - Ok(generate_mock_xcm_batch(0, 5)) + Ok(generate_mock_xcm_batch(0, 5).iter().map(|xcm| xcm.as_bounded_slice()).collect()) ); assert_eq!( XcmpQueue::take_first_concatenated_xcms(data, 5, &mut WeightMeter::new()), - Ok(generate_mock_xcm_batch(5, 4)) + Ok(generate_mock_xcm_batch(5, 4).iter().map(|xcm| xcm.as_bounded_slice()).collect()) ); // Should return partial batch on error @@ -770,7 +774,7 @@ fn take_first_concatenated_xcms_works() { page.extend(generate_mock_xcm(5).encode()); assert_eq!( XcmpQueue::take_first_concatenated_xcms(&mut &page[1..], 10, &mut WeightMeter::new()), - Err(generate_mock_xcm_batch(0, 5)) + Err(generate_mock_xcm_batch(0, 5).iter().map(|xcm| xcm.as_bounded_slice()).collect()) ); } diff --git a/cumulus/pallets/xcmp-queue/src/weights.rs b/cumulus/pallets/xcmp-queue/src/weights.rs index 5ae717a164bbb..dad34691d5907 100644 --- a/cumulus/pallets/xcmp-queue/src/weights.rs +++ b/cumulus/pallets/xcmp-queue/src/weights.rs @@ -16,7 +16,7 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-04-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Serbans-MacBook-Pro.local`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: `1024` @@ -55,7 +55,7 @@ pub trait WeightInfo { fn enqueue_1000_small_xcmp_messages() -> Weight; fn suspend_channel() -> Weight; fn resume_channel() -> Weight; - fn take_first_concatenated_xcm() -> Weight; + fn take_first_concatenated_xcm(n: u32, ) -> Weight; fn on_idle_good_msg() -> Weight; fn on_idle_large_msg() -> Weight; } @@ -67,10 +67,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `1497` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(3_000_000, 1497) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1497) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -87,12 +87,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 105467]`. fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_115_841, 5487) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(12_286_920, 5487) // Standard Error: 1 - .saturating_add(Weight::from_parts(155, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(194, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -109,12 +109,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(8_987_577, 5487) - // Standard Error: 313 - .saturating_add(Weight::from_parts(94_980, 0).saturating_mul(n.into())) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(13_439_195, 5487) + // Standard Error: 498 + .saturating_add(Weight::from_parts(130_951, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -129,12 +129,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 105457]`. fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `334 + n * (1 ±0)` + // Measured: `434 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(11_015_940, 108986) - // Standard Error: 32 - .saturating_add(Weight::from_parts(911, 0).saturating_mul(n.into())) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_354_447, 108986) + // Standard Error: 5 + .saturating_add(Weight::from_parts(747, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -151,12 +151,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. fn enqueue_n_full_pages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `186` + // Measured: `286` // Estimated: `5487` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(7_000_000, 5487) - // Standard Error: 20_150 - .saturating_add(Weight::from_parts(20_690_483, 0).saturating_mul(n.into())) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(10_000_000, 5487) + // Standard Error: 31_014 + .saturating_add(Weight::from_parts(24_068_862, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -171,10 +171,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) fn enqueue_1000_small_xcmp_messages() -> Weight { // Proof Size summary in bytes: - // Measured: `53067` + // Measured: `53167` // Estimated: `108986` - // Minimum execution time: 139_000_000 picoseconds. - Weight::from_parts(148_000_000, 108986) + // Minimum execution time: 172_000_000 picoseconds. + Weight::from_parts(181_000_000, 108986) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -182,9 +182,9 @@ impl WeightInfo for SubstrateWeight { /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn suspend_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `2767` - // Minimum execution time: 1_000_000 picoseconds. + // Minimum execution time: 2_000_000 picoseconds. Weight::from_parts(2_000_000, 2767) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -193,19 +193,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn resume_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `144` + // Measured: `210` // Estimated: `2767` // Minimum execution time: 2_000_000 picoseconds. Weight::from_parts(3_000_000, 2767) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(7_000_000, 0) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_825_791, 0) + // Standard Error: 564 + .saturating_add(Weight::from_parts(44_073, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -223,10 +226,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_good_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `105716` - // Estimated: `109181` - // Minimum execution time: 66_000_000 picoseconds. - Weight::from_parts(71_000_000, 109181) + // Measured: `105816` + // Estimated: `109281` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(67_000_000, 109281) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -246,10 +249,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_large_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `65785` - // Estimated: `69250` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_000_000, 69250) + // Measured: `65885` + // Estimated: `69350` + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(47_000_000, 69350) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -261,10 +264,10 @@ impl WeightInfo for () { /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `1497` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(3_000_000, 1497) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1497) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -281,12 +284,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 105467]`. fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_115_841, 5487) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(12_286_920, 5487) // Standard Error: 1 - .saturating_add(Weight::from_parts(155, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(194, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -303,12 +306,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(8_987_577, 5487) - // Standard Error: 313 - .saturating_add(Weight::from_parts(94_980, 0).saturating_mul(n.into())) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(13_439_195, 5487) + // Standard Error: 498 + .saturating_add(Weight::from_parts(130_951, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -323,12 +326,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 105457]`. fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `334 + n * (1 ±0)` + // Measured: `434 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(11_015_940, 108986) - // Standard Error: 32 - .saturating_add(Weight::from_parts(911, 0).saturating_mul(n.into())) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_354_447, 108986) + // Standard Error: 5 + .saturating_add(Weight::from_parts(747, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -345,12 +348,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. fn enqueue_n_full_pages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `186` + // Measured: `286` // Estimated: `5487` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(7_000_000, 5487) - // Standard Error: 20_150 - .saturating_add(Weight::from_parts(20_690_483, 0).saturating_mul(n.into())) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(10_000_000, 5487) + // Standard Error: 31_014 + .saturating_add(Weight::from_parts(24_068_862, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -365,10 +368,10 @@ impl WeightInfo for () { /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) fn enqueue_1000_small_xcmp_messages() -> Weight { // Proof Size summary in bytes: - // Measured: `53067` + // Measured: `53167` // Estimated: `108986` - // Minimum execution time: 139_000_000 picoseconds. - Weight::from_parts(148_000_000, 108986) + // Minimum execution time: 172_000_000 picoseconds. + Weight::from_parts(181_000_000, 108986) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -376,9 +379,9 @@ impl WeightInfo for () { /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn suspend_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `2767` - // Minimum execution time: 1_000_000 picoseconds. + // Minimum execution time: 2_000_000 picoseconds. Weight::from_parts(2_000_000, 2767) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -387,19 +390,22 @@ impl WeightInfo for () { /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn resume_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `144` + // Measured: `210` // Estimated: `2767` // Minimum execution time: 2_000_000 picoseconds. Weight::from_parts(3_000_000, 2767) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(7_000_000, 0) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_825_791, 0) + // Standard Error: 564 + .saturating_add(Weight::from_parts(44_073, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -417,10 +423,10 @@ impl WeightInfo for () { /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_good_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `105716` - // Estimated: `109181` - // Minimum execution time: 66_000_000 picoseconds. - Weight::from_parts(71_000_000, 109181) + // Measured: `105816` + // Estimated: `109281` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(67_000_000, 109281) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -440,10 +446,10 @@ impl WeightInfo for () { /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_large_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `65785` - // Estimated: `69250` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_000_000, 69250) + // Measured: `65885` + // Estimated: `69350` + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(47_000_000, 69350) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index ddc76fe451ad6..a5fe66fae5b0a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `109` // Estimated: `1497` - // Minimum execution time: 4_908_000 picoseconds. - Weight::from_parts(5_133_000, 0) + // Minimum execution time: 4_959_000 picoseconds. + Weight::from_parts(5_329_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `151` // Estimated: `5487` - // Minimum execution time: 13_653_000 picoseconds. - Weight::from_parts(9_457_298, 0) + // Minimum execution time: 14_349_000 picoseconds. + Weight::from_parts(9_748_630, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_016, 0).saturating_mul(n.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_042, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `151` // Estimated: `5487` - // Minimum execution time: 11_593_000 picoseconds. - Weight::from_parts(15_263_900, 0) + // Minimum execution time: 12_178_000 picoseconds. + Weight::from_parts(17_653_288, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 239 - .saturating_add(Weight::from_parts(136_065, 0).saturating_mul(n.into())) + // Standard Error: 291 + .saturating_add(Weight::from_parts(142_184, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `334 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 20_217_000 picoseconds. - Weight::from_parts(20_647_000, 0) + // Minimum execution time: 21_593_000 picoseconds. + Weight::from_parts(12_434_518, 0) .saturating_add(Weight::from_parts(0, 108986)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(2_576, 0).saturating_mul(n.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(2_294, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `186` // Estimated: `5487` - // Minimum execution time: 13_262_000 picoseconds. - Weight::from_parts(13_670_000, 0) + // Minimum execution time: 13_602_000 picoseconds. + Weight::from_parts(13_864_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 81_154 - .saturating_add(Weight::from_parts(105_979_285, 0).saturating_mul(n.into())) + // Standard Error: 96_416 + .saturating_add(Weight::from_parts(98_057_393, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `53067` // Estimated: `108986` - // Minimum execution time: 289_304_000 picoseconds. - Weight::from_parts(299_215_000, 0) + // Minimum execution time: 275_630_000 picoseconds. + Weight::from_parts(282_810_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `109` // Estimated: `2767` - // Minimum execution time: 3_121_000 picoseconds. - Weight::from_parts(3_254_000, 0) + // Minimum execution time: 3_200_000 picoseconds. + Weight::from_parts(3_393_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `144` // Estimated: `2767` - // Minimum execution time: 4_409_000 picoseconds. - Weight::from_parts(4_555_000, 0) + // Minimum execution time: 4_456_000 picoseconds. + Weight::from_parts(4_669_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_368_000 picoseconds. - Weight::from_parts(5_614_000, 0) + // Minimum execution time: 2_048_000 picoseconds. + Weight::from_parts(2_441_692, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 143 + .saturating_add(Weight::from_parts(17_966, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105716` // Estimated: `109181` - // Minimum execution time: 231_957_000 picoseconds. - Weight::from_parts(242_676_000, 0) + // Minimum execution time: 187_620_000 picoseconds. + Weight::from_parts(209_054_000, 0) .saturating_add(Weight::from_parts(0, 109181)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65785` // Estimated: `69250` - // Minimum execution time: 134_722_000 picoseconds. - Weight::from_parts(138_495_000, 0) + // Minimum execution time: 126_787_000 picoseconds. + Weight::from_parts(133_110_000, 0) .saturating_add(Weight::from_parts(0, 69250)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs index a3e0129468d65..0d303d5c77eb0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: Some(12), added: 507, mode: `MaxEncodedLen`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `1497` - // Minimum execution time: 4_883_000 picoseconds. - Weight::from_parts(5_223_000, 0) + // Minimum execution time: 5_238_000 picoseconds. + Weight::from_parts(5_695_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -75,13 +75,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 105467]`. fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 13_840_000 picoseconds. - Weight::from_parts(8_982_973, 0) + // Minimum execution time: 15_235_000 picoseconds. + Weight::from_parts(11_414_155, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(995, 0).saturating_mul(n.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_044, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -98,13 +98,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 1000]`. fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `251` // Estimated: `5487` - // Minimum execution time: 12_129_000 picoseconds. - Weight::from_parts(15_937_292, 0) + // Minimum execution time: 12_885_000 picoseconds. + Weight::from_parts(17_648_279, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 225 - .saturating_add(Weight::from_parts(115_324, 0).saturating_mul(n.into())) + // Standard Error: 260 + .saturating_add(Weight::from_parts(146_465, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -119,13 +119,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 105457]`. fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `334 + n * (1 ±0)` + // Measured: `434 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 20_484_000 picoseconds. - Weight::from_parts(20_648_000, 0) + // Minimum execution time: 24_912_000 picoseconds. + Weight::from_parts(16_404_977, 0) .saturating_add(Weight::from_parts(0, 108986)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(2_365, 0).saturating_mul(n.into())) + // Standard Error: 14 + .saturating_add(Weight::from_parts(2_304, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -142,13 +142,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 100]`. fn enqueue_n_full_pages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `186` + // Measured: `286` // Estimated: `5487` - // Minimum execution time: 12_963_000 picoseconds. - Weight::from_parts(13_277_000, 0) + // Minimum execution time: 14_636_000 picoseconds. + Weight::from_parts(15_119_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 63_306 - .saturating_add(Weight::from_parts(104_765_134, 0).saturating_mul(n.into())) + // Standard Error: 78_913 + .saturating_add(Weight::from_parts(98_091_696, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -163,10 +163,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) fn enqueue_1000_small_xcmp_messages() -> Weight { // Proof Size summary in bytes: - // Measured: `53067` + // Measured: `53167` // Estimated: `108986` - // Minimum execution time: 255_661_000 picoseconds. - Weight::from_parts(264_825_000, 0) + // Minimum execution time: 281_890_000 picoseconds. + Weight::from_parts(301_578_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -175,10 +175,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn suspend_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `175` // Estimated: `2767` - // Minimum execution time: 3_092_000 picoseconds. - Weight::from_parts(3_339_000, 0) + // Minimum execution time: 3_559_000 picoseconds. + Weight::from_parts(3_941_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -187,21 +187,24 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn resume_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `144` + // Measured: `210` // Estimated: `2767` - // Minimum execution time: 4_352_000 picoseconds. - Weight::from_parts(4_577_000, 0) + // Minimum execution time: 4_747_000 picoseconds. + Weight::from_parts(5_000_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_050_000 picoseconds. - Weight::from_parts(5_270_000, 0) + // Minimum execution time: 1_983_000 picoseconds. + Weight::from_parts(2_340_802, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 95 + .saturating_add(Weight::from_parts(17_197, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -219,11 +222,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_good_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `105716` - // Estimated: `109181` - // Minimum execution time: 210_820_000 picoseconds. - Weight::from_parts(221_925_000, 0) - .saturating_add(Weight::from_parts(0, 109181)) + // Measured: `105816` + // Estimated: `109281` + // Minimum execution time: 191_606_000 picoseconds. + Weight::from_parts(204_871_000, 0) + .saturating_add(Weight::from_parts(0, 109281)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -243,11 +246,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_large_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `65785` - // Estimated: `69250` - // Minimum execution time: 127_555_000 picoseconds. - Weight::from_parts(130_147_000, 0) - .saturating_add(Weight::from_parts(0, 69250)) + // Measured: `65885` + // Estimated: `69350` + // Minimum execution time: 127_183_000 picoseconds. + Weight::from_parts(133_929_000, 0) + .saturating_add(Weight::from_parts(0, 69350)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 40f13c7090b47..e96a8ab5a5b6b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `4` // Estimated: `1497` - // Minimum execution time: 4_326_000 picoseconds. - Weight::from_parts(4_616_000, 0) + // Minimum execution time: 4_460_000 picoseconds. + Weight::from_parts(4_675_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `80` // Estimated: `5487` - // Minimum execution time: 13_374_000 picoseconds. - Weight::from_parts(9_220_505, 0) + // Minimum execution time: 14_234_000 picoseconds. + Weight::from_parts(9_599_674, 0) .saturating_add(Weight::from_parts(0, 5487)) // Standard Error: 6 - .saturating_add(Weight::from_parts(989, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_047, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `80` // Estimated: `5487` - // Minimum execution time: 11_436_000 picoseconds. - Weight::from_parts(15_588_934, 0) + // Minimum execution time: 12_070_000 picoseconds. + Weight::from_parts(16_440_071, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 215 - .saturating_add(Weight::from_parts(121_183, 0).saturating_mul(n.into())) + // Standard Error: 266 + .saturating_add(Weight::from_parts(146_239, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `263 + n * (1 ±0)` // Estimated: `109014` - // Minimum execution time: 21_929_000 picoseconds. - Weight::from_parts(1_150_129, 0) + // Minimum execution time: 23_688_000 picoseconds. + Weight::from_parts(14_746_605, 0) .saturating_add(Weight::from_parts(0, 109014)) - // Standard Error: 16 - .saturating_add(Weight::from_parts(2_654, 0).saturating_mul(n.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(2_328, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `115` // Estimated: `5487` - // Minimum execution time: 12_994_000 picoseconds. - Weight::from_parts(13_450_000, 0) + // Minimum execution time: 13_401_000 picoseconds. + Weight::from_parts(13_651_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 59_142 - .saturating_add(Weight::from_parts(101_994_623, 0).saturating_mul(n.into())) + // Standard Error: 70_006 + .saturating_add(Weight::from_parts(97_625_139, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `52996` // Estimated: `109014` - // Minimum execution time: 266_450_000 picoseconds. - Weight::from_parts(274_887_000, 0) + // Minimum execution time: 288_846_000 picoseconds. + Weight::from_parts(297_120_000, 0) .saturating_add(Weight::from_parts(0, 109014)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `4` // Estimated: `2767` - // Minimum execution time: 2_388_000 picoseconds. - Weight::from_parts(2_520_000, 0) + // Minimum execution time: 2_567_000 picoseconds. + Weight::from_parts(2_706_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `39` // Estimated: `2767` - // Minimum execution time: 3_782_000 picoseconds. - Weight::from_parts(3_940_000, 0) + // Minimum execution time: 3_781_000 picoseconds. + Weight::from_parts(3_998_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_418_000 picoseconds. - Weight::from_parts(5_613_000, 0) + // Minimum execution time: 2_079_000 picoseconds. + Weight::from_parts(2_410_204, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 97 + .saturating_add(Weight::from_parts(17_210, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105645` // Estimated: `109110` - // Minimum execution time: 210_814_000 picoseconds. - Weight::from_parts(217_016_000, 0) + // Minimum execution time: 192_718_000 picoseconds. + Weight::from_parts(203_462_000, 0) .saturating_add(Weight::from_parts(0, 109110)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65714` // Estimated: `69179` - // Minimum execution time: 126_881_000 picoseconds. - Weight::from_parts(131_302_000, 0) + // Minimum execution time: 125_934_000 picoseconds. + Weight::from_parts(129_980_000, 0) .saturating_add(Weight::from_parts(0, 69179)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs index f8a44aa4779c9..87969cb8abfe3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `142` // Estimated: `1497` - // Minimum execution time: 5_195_000 picoseconds. - Weight::from_parts(5_568_000, 0) + // Minimum execution time: 5_022_000 picoseconds. + Weight::from_parts(5_424_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `148` // Estimated: `5487` - // Minimum execution time: 13_430_000 picoseconds. - Weight::from_parts(9_574_197, 0) + // Minimum execution time: 14_324_000 picoseconds. + Weight::from_parts(9_117_035, 0) .saturating_add(Weight::from_parts(0, 5487)) // Standard Error: 6 - .saturating_add(Weight::from_parts(973, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_053, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `148` // Estimated: `5487` - // Minimum execution time: 11_564_000 picoseconds. - Weight::from_parts(15_506_334, 0) + // Minimum execution time: 11_747_000 picoseconds. + Weight::from_parts(16_504_385, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 205 - .saturating_add(Weight::from_parts(114_494, 0).saturating_mul(n.into())) + // Standard Error: 230 + .saturating_add(Weight::from_parts(147_286, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `330 + n * (1 ±0)` // Estimated: `109014` - // Minimum execution time: 19_772_000 picoseconds. - Weight::from_parts(20_089_000, 0) + // Minimum execution time: 21_596_000 picoseconds. + Weight::from_parts(11_861_199, 0) .saturating_add(Weight::from_parts(0, 109014)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(2_427, 0).saturating_mul(n.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(2_291, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `183` // Estimated: `5487` - // Minimum execution time: 12_651_000 picoseconds. - Weight::from_parts(13_268_000, 0) + // Minimum execution time: 13_488_000 picoseconds. + Weight::from_parts(13_700_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 55_621 - .saturating_add(Weight::from_parts(102_763_421, 0).saturating_mul(n.into())) + // Standard Error: 89_638 + .saturating_add(Weight::from_parts(98_160_015, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `53063` // Estimated: `109014` - // Minimum execution time: 252_294_000 picoseconds. - Weight::from_parts(260_540_000, 0) + // Minimum execution time: 283_182_000 picoseconds. + Weight::from_parts(292_377_000, 0) .saturating_add(Weight::from_parts(0, 109014)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `142` // Estimated: `2767` - // Minimum execution time: 3_337_000 picoseconds. - Weight::from_parts(3_498_000, 0) + // Minimum execution time: 3_375_000 picoseconds. + Weight::from_parts(3_603_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `177` // Estimated: `2767` - // Minimum execution time: 4_674_000 picoseconds. - Weight::from_parts(4_822_000, 0) + // Minimum execution time: 4_447_000 picoseconds. + Weight::from_parts(4_769_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_045_000 picoseconds. - Weight::from_parts(5_399_000, 0) + // Minimum execution time: 2_172_000 picoseconds. + Weight::from_parts(2_524_868, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 195 + .saturating_add(Weight::from_parts(17_700, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105713` // Estimated: `109178` - // Minimum execution time: 211_435_000 picoseconds. - Weight::from_parts(222_691_000, 0) + // Minimum execution time: 187_431_000 picoseconds. + Weight::from_parts(199_807_000, 0) .saturating_add(Weight::from_parts(0, 109178)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65782` // Estimated: `69247` - // Minimum execution time: 126_438_000 picoseconds. - Weight::from_parts(129_423_000, 0) + // Minimum execution time: 122_370_000 picoseconds. + Weight::from_parts(130_426_000, 0) .saturating_add(Weight::from_parts(0, 69247)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs index bed529edcea33..332320b527657 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `142` // Estimated: `1497` - // Minimum execution time: 4_975_000 picoseconds. - Weight::from_parts(5_353_000, 0) + // Minimum execution time: 5_163_000 picoseconds. + Weight::from_parts(5_403_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -75,13 +75,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 105467]`. fn enqueue_n_bytes_xcmp_message(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `148` + // Measured: `184` // Estimated: `5487` - // Minimum execution time: 13_084_000 picoseconds. - Weight::from_parts(8_989_453, 0) + // Minimum execution time: 14_411_000 picoseconds. + Weight::from_parts(9_821_468, 0) .saturating_add(Weight::from_parts(0, 5487)) // Standard Error: 6 - .saturating_add(Weight::from_parts(1_026, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(965, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -98,13 +98,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 1000]`. fn enqueue_n_empty_xcmp_messages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `148` + // Measured: `184` // Estimated: `5487` - // Minimum execution time: 10_913_000 picoseconds. - Weight::from_parts(14_988_541, 0) + // Minimum execution time: 12_086_000 picoseconds. + Weight::from_parts(17_308_897, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 235 - .saturating_add(Weight::from_parts(130_851, 0).saturating_mul(n.into())) + // Standard Error: 271 + .saturating_add(Weight::from_parts(144_787, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -119,13 +119,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 105457]`. fn enqueue_empty_xcmp_message_at(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `330 + n * (1 ±0)` + // Measured: `367 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 19_799_000 picoseconds. - Weight::from_parts(20_095_000, 0) + // Minimum execution time: 21_448_000 picoseconds. + Weight::from_parts(12_714_843, 0) .saturating_add(Weight::from_parts(0, 108986)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(2_584, 0).saturating_mul(n.into())) + // Standard Error: 11 + .saturating_add(Weight::from_parts(2_056, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -142,13 +142,13 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// The range of component `n` is `[0, 100]`. fn enqueue_n_full_pages(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `183` + // Measured: `219` // Estimated: `5487` - // Minimum execution time: 12_421_000 picoseconds. - Weight::from_parts(12_780_000, 0) + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(13_915_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 84_412 - .saturating_add(Weight::from_parts(106_740_006, 0).saturating_mul(n.into())) + // Standard Error: 68_118 + .saturating_add(Weight::from_parts(90_488_147, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -163,10 +163,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) fn enqueue_1000_small_xcmp_messages() -> Weight { // Proof Size summary in bytes: - // Measured: `53063` + // Measured: `53100` // Estimated: `108986` - // Minimum execution time: 279_435_000 picoseconds. - Weight::from_parts(285_825_000, 0) + // Minimum execution time: 268_288_000 picoseconds. + Weight::from_parts(273_155_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `142` // Estimated: `2767` - // Minimum execution time: 3_187_000 picoseconds. - Weight::from_parts(3_390_000, 0) + // Minimum execution time: 3_196_000 picoseconds. + Weight::from_parts(3_456_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `177` // Estimated: `2767` - // Minimum execution time: 4_450_000 picoseconds. - Weight::from_parts(4_688_000, 0) + // Minimum execution time: 4_468_000 picoseconds. + Weight::from_parts(4_880_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_199_000 picoseconds. - Weight::from_parts(5_368_000, 0) + // Minimum execution time: 2_003_000 picoseconds. + Weight::from_parts(2_438_969, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 175 + .saturating_add(Weight::from_parts(17_883, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -219,11 +222,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_good_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `105713` - // Estimated: `109178` - // Minimum execution time: 229_715_000 picoseconds. - Weight::from_parts(232_586_000, 0) - .saturating_add(Weight::from_parts(0, 109178)) + // Measured: `105749` + // Estimated: `109214` + // Minimum execution time: 177_632_000 picoseconds. + Weight::from_parts(186_057_000, 0) + .saturating_add(Weight::from_parts(0, 109214)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -243,11 +246,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) fn on_idle_large_msg() -> Weight { // Proof Size summary in bytes: - // Measured: `65782` - // Estimated: `69247` - // Minimum execution time: 133_351_000 picoseconds. - Weight::from_parts(135_787_000, 0) - .saturating_add(Weight::from_parts(0, 69247)) + // Measured: `65818` + // Estimated: `69283` + // Minimum execution time: 116_557_000 picoseconds. + Weight::from_parts(120_206_000, 0) + .saturating_add(Weight::from_parts(0, 69283)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 5051a8c8e96b2..bccbf7df370eb 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1497` - // Minimum execution time: 4_788_000 picoseconds. - Weight::from_parts(5_033_000, 0) + // Minimum execution time: 5_033_000 picoseconds. + Weight::from_parts(5_335_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 12_649_000 picoseconds. - Weight::from_parts(8_733_180, 0) + // Minimum execution time: 13_695_000 picoseconds. + Weight::from_parts(9_707_464, 0) .saturating_add(Weight::from_parts(0, 5487)) // Standard Error: 6 - .saturating_add(Weight::from_parts(982, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(946, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 10_604_000 picoseconds. - Weight::from_parts(14_570_286, 0) + // Minimum execution time: 11_606_000 picoseconds. + Weight::from_parts(15_497_649, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 193 - .saturating_add(Weight::from_parts(117_011, 0).saturating_mul(n.into())) + // Standard Error: 383 + .saturating_add(Weight::from_parts(144_897, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `264 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 19_467_000 picoseconds. - Weight::from_parts(19_689_000, 0) + // Minimum execution time: 20_569_000 picoseconds. + Weight::from_parts(12_353_232, 0) .saturating_add(Weight::from_parts(0, 108986)) // Standard Error: 11 - .saturating_add(Weight::from_parts(2_365, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_033, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `117` // Estimated: `5487` - // Minimum execution time: 12_234_000 picoseconds. - Weight::from_parts(12_623_000, 0) + // Minimum execution time: 13_109_000 picoseconds. + Weight::from_parts(13_377_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 62_233 - .saturating_add(Weight::from_parts(102_929_572, 0).saturating_mul(n.into())) + // Standard Error: 87_993 + .saturating_add(Weight::from_parts(91_358_719, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `52997` // Estimated: `108986` - // Minimum execution time: 254_750_000 picoseconds. - Weight::from_parts(262_602_000, 0) + // Minimum execution time: 264_958_000 picoseconds. + Weight::from_parts(270_387_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `2767` - // Minimum execution time: 2_920_000 picoseconds. - Weight::from_parts(3_228_000, 0) + // Minimum execution time: 3_267_000 picoseconds. + Weight::from_parts(3_446_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `111` // Estimated: `2767` - // Minimum execution time: 4_301_000 picoseconds. - Weight::from_parts(4_501_000, 0) + // Minimum execution time: 4_396_000 picoseconds. + Weight::from_parts(4_516_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_274_000 picoseconds. - Weight::from_parts(5_575_000, 0) + // Minimum execution time: 2_001_000 picoseconds. + Weight::from_parts(2_478_301, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 143 + .saturating_add(Weight::from_parts(17_452, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105647` // Estimated: `109112` - // Minimum execution time: 212_251_000 picoseconds. - Weight::from_parts(220_677_000, 0) + // Minimum execution time: 174_001_000 picoseconds. + Weight::from_parts(178_058_000, 0) .saturating_add(Weight::from_parts(0, 109112)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65716` // Estimated: `69181` - // Minimum execution time: 125_236_000 picoseconds. - Weight::from_parts(127_502_000, 0) + // Minimum execution time: 116_008_000 picoseconds. + Weight::from_parts(118_667_000, 0) .saturating_add(Weight::from_parts(0, 69181)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs index 7aa9c8a0896c2..dbb67783fdebf 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1497` - // Minimum execution time: 4_864_000 picoseconds. - Weight::from_parts(5_179_000, 0) + // Minimum execution time: 4_928_000 picoseconds. + Weight::from_parts(5_358_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 12_962_000 picoseconds. - Weight::from_parts(8_522_179, 0) + // Minimum execution time: 14_370_000 picoseconds. + Weight::from_parts(9_971_021, 0) .saturating_add(Weight::from_parts(0, 5487)) // Standard Error: 6 - .saturating_add(Weight::from_parts(1_028, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(941, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 10_903_000 picoseconds. - Weight::from_parts(14_761_815, 0) + // Minimum execution time: 11_949_000 picoseconds. + Weight::from_parts(16_605_001, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 200 - .saturating_add(Weight::from_parts(117_611, 0).saturating_mul(n.into())) + // Standard Error: 316 + .saturating_add(Weight::from_parts(146_307, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `264 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 19_215_000 picoseconds. - Weight::from_parts(19_684_000, 0) + // Minimum execution time: 21_297_000 picoseconds. + Weight::from_parts(13_185_882, 0) .saturating_add(Weight::from_parts(0, 108986)) // Standard Error: 12 - .saturating_add(Weight::from_parts(2_568, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_037, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `117` // Estimated: `5487` - // Minimum execution time: 12_217_000 picoseconds. - Weight::from_parts(12_477_000, 0) + // Minimum execution time: 13_210_000 picoseconds. + Weight::from_parts(13_504_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 55_582 - .saturating_add(Weight::from_parts(106_437_894, 0).saturating_mul(n.into())) + // Standard Error: 64_713 + .saturating_add(Weight::from_parts(90_594_857, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `52997` // Estimated: `108986` - // Minimum execution time: 264_971_000 picoseconds. - Weight::from_parts(275_172_000, 0) + // Minimum execution time: 269_027_000 picoseconds. + Weight::from_parts(285_137_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `2767` - // Minimum execution time: 2_996_000 picoseconds. - Weight::from_parts(3_216_000, 0) + // Minimum execution time: 3_058_000 picoseconds. + Weight::from_parts(3_349_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `111` // Estimated: `2767` - // Minimum execution time: 4_320_000 picoseconds. - Weight::from_parts(4_499_000, 0) + // Minimum execution time: 4_268_000 picoseconds. + Weight::from_parts(4_503_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_044_000 picoseconds. - Weight::from_parts(5_145_000, 0) + // Minimum execution time: 2_005_000 picoseconds. + Weight::from_parts(2_414_620, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 257 + .saturating_add(Weight::from_parts(19_194, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105647` // Estimated: `109112` - // Minimum execution time: 223_930_000 picoseconds. - Weight::from_parts(234_241_000, 0) + // Minimum execution time: 177_174_000 picoseconds. + Weight::from_parts(181_060_000, 0) .saturating_add(Weight::from_parts(0, 109112)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65716` // Estimated: `69181` - // Minimum execution time: 132_117_000 picoseconds. - Weight::from_parts(134_663_000, 0) + // Minimum execution time: 116_529_000 picoseconds. + Weight::from_parts(118_305_000, 0) .saturating_add(Weight::from_parts(0, 69181)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 32ae0f05dadba..ceab118a036d6 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1497` - // Minimum execution time: 4_894_000 picoseconds. - Weight::from_parts(5_140_000, 0) + // Minimum execution time: 5_057_000 picoseconds. + Weight::from_parts(5_254_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 13_062_000 picoseconds. - Weight::from_parts(8_854_073, 0) + // Minimum execution time: 13_643_000 picoseconds. + Weight::from_parts(9_652_139, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(985, 0).saturating_mul(n.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_039, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 10_915_000 picoseconds. - Weight::from_parts(14_766_724, 0) + // Minimum execution time: 11_614_000 picoseconds. + Weight::from_parts(15_847_295, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 228 - .saturating_add(Weight::from_parts(117_905, 0).saturating_mul(n.into())) + // Standard Error: 243 + .saturating_add(Weight::from_parts(145_536, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `264 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 19_506_000 picoseconds. - Weight::from_parts(19_645_000, 0) + // Minimum execution time: 20_891_000 picoseconds. + Weight::from_parts(12_137_030, 0) .saturating_add(Weight::from_parts(0, 108986)) // Standard Error: 12 - .saturating_add(Weight::from_parts(2_407, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_290, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `117` // Estimated: `5487` - // Minimum execution time: 12_218_000 picoseconds. - Weight::from_parts(12_586_000, 0) + // Minimum execution time: 13_104_000 picoseconds. + Weight::from_parts(13_302_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 105_927 - .saturating_add(Weight::from_parts(101_388_985, 0).saturating_mul(n.into())) + // Standard Error: 76_089 + .saturating_add(Weight::from_parts(98_243_339, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `52997` // Estimated: `108986` - // Minimum execution time: 253_077_000 picoseconds. - Weight::from_parts(257_994_000, 0) + // Minimum execution time: 280_014_000 picoseconds. + Weight::from_parts(291_117_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `2767` - // Minimum execution time: 3_102_000 picoseconds. - Weight::from_parts(3_289_000, 0) + // Minimum execution time: 3_280_000 picoseconds. + Weight::from_parts(3_455_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `111` // Estimated: `2767` - // Minimum execution time: 4_386_000 picoseconds. - Weight::from_parts(4_658_000, 0) + // Minimum execution time: 4_477_000 picoseconds. + Weight::from_parts(4_728_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_154_000 picoseconds. - Weight::from_parts(5_368_000, 0) + // Minimum execution time: 2_028_000 picoseconds. + Weight::from_parts(2_386_598, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 125 + .saturating_add(Weight::from_parts(18_383, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105647` // Estimated: `109112` - // Minimum execution time: 209_858_000 picoseconds. - Weight::from_parts(220_504_000, 0) + // Minimum execution time: 183_291_000 picoseconds. + Weight::from_parts(195_539_000, 0) .saturating_add(Weight::from_parts(0, 109112)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65716` // Estimated: `69181` - // Minimum execution time: 127_163_000 picoseconds. - Weight::from_parts(132_512_000, 0) + // Minimum execution time: 121_905_000 picoseconds. + Weight::from_parts(129_494_000, 0) .saturating_add(Weight::from_parts(0, 69181)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_xcmp_queue.rs index 7159ed0809bd9..1aeff1e6f5ed1 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/cumulus_pallet_xcmp_queue.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-05-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `16d5a52ef0dc`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `b8d1375f7728`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `1497` - // Minimum execution time: 4_910_000 picoseconds. - Weight::from_parts(5_170_000, 0) + // Minimum execution time: 5_237_000 picoseconds. + Weight::from_parts(5_369_000, 0) .saturating_add(Weight::from_parts(0, 1497)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,11 +77,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 12_705_000 picoseconds. - Weight::from_parts(8_172_546, 0) + // Minimum execution time: 13_997_000 picoseconds. + Weight::from_parts(10_370_954, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_028, 0).saturating_mul(n.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_001, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -100,11 +100,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `82` // Estimated: `5487` - // Minimum execution time: 10_949_000 picoseconds. - Weight::from_parts(14_462_029, 0) + // Minimum execution time: 11_600_000 picoseconds. + Weight::from_parts(16_515_274, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 201 - .saturating_add(Weight::from_parts(119_824, 0).saturating_mul(n.into())) + // Standard Error: 246 + .saturating_add(Weight::from_parts(145_121, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -121,11 +121,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `264 + n * (1 ±0)` // Estimated: `108986` - // Minimum execution time: 19_543_000 picoseconds. - Weight::from_parts(19_802_000, 0) + // Minimum execution time: 20_767_000 picoseconds. + Weight::from_parts(11_519_699, 0) .saturating_add(Weight::from_parts(0, 108986)) // Standard Error: 12 - .saturating_add(Weight::from_parts(2_565, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_307, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -144,11 +144,11 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `117` // Estimated: `5487` - // Minimum execution time: 12_500_000 picoseconds. - Weight::from_parts(12_672_000, 0) + // Minimum execution time: 13_110_000 picoseconds. + Weight::from_parts(13_275_000, 0) .saturating_add(Weight::from_parts(0, 5487)) - // Standard Error: 221_916 - .saturating_add(Weight::from_parts(106_306_015, 0).saturating_mul(n.into())) + // Standard Error: 65_885 + .saturating_add(Weight::from_parts(97_483_896, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -165,8 +165,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `52997` // Estimated: `108986` - // Minimum execution time: 266_767_000 picoseconds. - Weight::from_parts(275_163_000, 0) + // Minimum execution time: 278_359_000 picoseconds. + Weight::from_parts(286_253_000, 0) .saturating_add(Weight::from_parts(0, 108986)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -177,8 +177,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `76` // Estimated: `2767` - // Minimum execution time: 2_950_000 picoseconds. - Weight::from_parts(3_180_000, 0) + // Minimum execution time: 3_289_000 picoseconds. + Weight::from_parts(3_396_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -189,19 +189,22 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `111` // Estimated: `2767` - // Minimum execution time: 4_530_000 picoseconds. - Weight::from_parts(4_798_000, 0) + // Minimum execution time: 4_435_000 picoseconds. + Weight::from_parts(4_724_000, 0) .saturating_add(Weight::from_parts(0, 2767)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_231_000 picoseconds. - Weight::from_parts(5_399_000, 0) + // Minimum execution time: 2_039_000 picoseconds. + Weight::from_parts(2_426_754, 0) .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 153 + .saturating_add(Weight::from_parts(17_160, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) @@ -221,8 +224,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `105647` // Estimated: `109112` - // Minimum execution time: 227_766_000 picoseconds. - Weight::from_parts(236_600_000, 0) + // Minimum execution time: 187_032_000 picoseconds. + Weight::from_parts(203_070_000, 0) .saturating_add(Weight::from_parts(0, 109112)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -245,8 +248,8 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `65716` // Estimated: `69181` - // Minimum execution time: 132_541_000 picoseconds. - Weight::from_parts(135_781_000, 0) + // Minimum execution time: 121_653_000 picoseconds. + Weight::from_parts(131_943_000, 0) .saturating_add(Weight::from_parts(0, 69181)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) diff --git a/prdoc/pr_9539.prdoc b/prdoc/pr_9539.prdoc new file mode 100644 index 0000000000000..edfd6b9bde2f0 --- /dev/null +++ b/prdoc/pr_9539.prdoc @@ -0,0 +1,28 @@ +title: '[XCMP] `take_first_concatenated_xcm()` improvements' +doc: +- audience: Runtime Dev + description: |- + This PR: + - improves `take_first_concatenated_xcm()` avoiding the XCM re-encoding + - makes the benchmarks for `take_first_concatenated_xcm()` more granular, accounting for the number of bytes of the message +crates: +- name: cumulus-pallet-xcmp-queue + bump: major +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch +- name: collectives-westend-runtime + bump: patch +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch +- name: people-rococo-runtime + bump: patch +- name: people-westend-runtime + bump: patch diff --git a/substrate/frame/staking-async/runtimes/parachain/src/weights/cumulus_pallet_xcmp_queue.rs b/substrate/frame/staking-async/runtimes/parachain/src/weights/cumulus_pallet_xcmp_queue.rs index 60543220d68c1..e001f2a2972e1 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/weights/cumulus_pallet_xcmp_queue.rs @@ -186,12 +186,15 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn take_first_concatenated_xcm() -> Weight { + /// The range of component `n` is `[0, 92]`. + fn take_first_concatenated_xcm(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_749_000 picoseconds. - Weight::from_parts(5_937_000, 0) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_806_940, 0) + // Standard Error: 541 + .saturating_add(Weight::from_parts(46_068, 0).saturating_mul(n.into())) } /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) From 1475ba1300d4adcebfa0394bb7e5b9b00a6c7bb1 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 25 Aug 2025 13:04:31 +0200 Subject: [PATCH 15/16] Society pallet supports non-consecutive block provider (#9497) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Society pallet supports non-consecutive block provider Society pallet correctly handles situations where `on_initialize` is invoked with block numbers that: - increase but are not strictly consecutive (e.g., jump from 5 → 10), or - are repeated (e.g., multiple blocks are built at the same Relay Chain parent block, all reporting the same BlockNumberProvider value). This situation may occur when the BlockNumberProvider is not local - for example, on a parachain using the Relay Chain block number provider. --------- Co-authored-by: Oliver Tale-Yazdi --- prdoc/pr_9497.prdoc | 12 ++ substrate/frame/society/src/lib.rs | 102 ++++++++++++-- substrate/frame/society/src/mock.rs | 4 +- substrate/frame/society/src/tests.rs | 191 +++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 15 deletions(-) create mode 100644 prdoc/pr_9497.prdoc diff --git a/prdoc/pr_9497.prdoc b/prdoc/pr_9497.prdoc new file mode 100644 index 0000000000000..c4f0b0b0bb416 --- /dev/null +++ b/prdoc/pr_9497.prdoc @@ -0,0 +1,12 @@ +title: 'Society pallet supports non-consecutive block provider' +doc: +- audience: Runtime Dev + description: |- + Society pallet correctly handles situations where on_initialize is invoked with block numbers that: + - increase but are not strictly consecutive (e.g., jump from 5 → 10), or + - are repeated (e.g., multiple blocks are built at the same Relay Chain parent block, all reporting the same BlockNumberProvider value). + This situation may occur when the BlockNumberProvider is not local - for example, on a parachain using the Relay Chain block number provider. + +crates: +- name: pallet-society + bump: major diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index 5590ccf7e3e0a..9be673f2e1daa 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -519,13 +519,14 @@ pub mod pallet { #[pallet::constant] type PeriodSpend: Get>; - /// The number of blocks on which new candidates should be voted on. Together with + /// The number of [Config::BlockNumberProvider] blocks on which new candidates should be + /// voted on. Together with /// `ClaimPeriod`, this sums to the number of blocks between candidate intake periods. #[pallet::constant] type VotingPeriod: Get>; - /// The number of blocks on which new candidates can claim their membership and be the - /// named head. + /// The number of [Config::BlockNumberProvider] blocks on which new candidates can claim + /// their membership and be the named head. #[pallet::constant] type ClaimPeriod: Get>; @@ -536,9 +537,9 @@ pub mod pallet { /// The origin that is allowed to call `found`. type FounderSetOrigin: EnsureOrigin; - /// The number of blocks between membership challenges. + /// The number of [Config::BlockNumberProvider] blocks between membership challenges. #[pallet::constant] - type ChallengePeriod: Get>; + type ChallengePeriod: Get>; /// The maximum number of payouts a member may have waiting unclaimed. #[pallet::constant] @@ -784,11 +785,20 @@ pub mod pallet { pub type DefenderVotes, I: 'static = ()> = StorageDoubleMap<_, Twox64Concat, RoundIndex, Twox64Concat, T::AccountId, Vote>; + /// Next intake rotation scheduled with [Config::BlockNumberProvider]. + #[pallet::storage] + pub type NextIntakeAt, I: 'static = ()> = StorageValue<_, BlockNumberFor>; + + /// Next challenge rotation scheduled with [Config::BlockNumberProvider]. + #[pallet::storage] + pub type NextChallengeAt, I: 'static = ()> = StorageValue<_, BlockNumberFor>; + #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { - fn on_initialize(n: SystemBlockNumberFor) -> Weight { + fn on_initialize(_n: SystemBlockNumberFor) -> Weight { let mut weight = Weight::zero(); let weights = T::BlockWeights::get(); + let now = T::BlockNumberProvider::current_block_number(); let phrase = b"society_rotation"; // we'll need a random seed here. @@ -801,18 +811,21 @@ pub mod pallet { let mut rng = ChaChaRng::from_seed(seed); // Run a candidate/membership rotation - match Self::period() { - Period::Voting { elapsed, .. } if elapsed.is_zero() => { - Self::rotate_intake(&mut rng); - weight.saturating_accrue(weights.max_block / 20); - }, - _ => {}, + let is_intake_moment = match Self::period() { + Period::Intake { .. } => true, + _ => false, + }; + if is_intake_moment { + Self::rotate_intake(&mut rng); + weight.saturating_accrue(weights.max_block / 20); + Self::set_next_intake_at(); } // Run a challenge rotation - if (n % T::ChallengePeriod::get()).is_zero() { + if now >= Self::next_challenge_at() { Self::rotate_challenge(&mut rng); weight.saturating_accrue(weights.max_block / 20); + Self::set_next_challenge_at(); } weight @@ -1475,9 +1488,11 @@ impl_ensure_origin_with_arg_ignoring_arg! { {} } +#[derive(Debug, PartialEq, Eq)] pub enum Period { Voting { elapsed: BlockNumber, more: BlockNumber }, Claim { elapsed: BlockNumber, more: BlockNumber }, + Intake { elapsed: BlockNumber }, } impl, I: 'static> Pallet { @@ -1488,13 +1503,72 @@ impl, I: 'static> Pallet { let rotation_period = voting_period + claim_period; let now = T::BlockNumberProvider::current_block_number(); let phase = now % rotation_period; - if phase < voting_period { + if now >= Self::next_intake_at() { + Period::Intake { elapsed: now - Self::next_intake_at() } + } else if phase < voting_period { Period::Voting { elapsed: phase, more: voting_period - phase } } else { Period::Claim { elapsed: phase - voting_period, more: rotation_period - phase } } } + /// Next intake (candidate/membership) rotation scheduled with [Config::BlockNumberProvider]. + /// + /// Rounds the previous block number up to the next rotation period (voting + claim periods). + pub fn next_intake_at() -> BlockNumberFor { + match NextIntakeAt::::get() { + Some(next) => next, + None => { + // executed once. + let now = T::BlockNumberProvider::current_block_number(); + let prev_block = now.saturating_sub(BlockNumberFor::::one()); + let rotation_period = T::VotingPeriod::get().saturating_add(T::ClaimPeriod::get()); + let elapsed = prev_block % rotation_period; + let next_intake_at = prev_block + (rotation_period - elapsed); + NextIntakeAt::::put(next_intake_at); + next_intake_at + }, + } + } + + /// Set the next intake (candidate/membership) rotation. + /// + /// This supposed to be called once the current intake is executed. + fn set_next_intake_at() { + let prev_next_intake_at = Self::next_intake_at(); + let next_intake_at = prev_next_intake_at + .saturating_add(T::VotingPeriod::get().saturating_add(T::ClaimPeriod::get())); + NextIntakeAt::::put(next_intake_at); + } + + /// Returns the next challenge rotation scheduled with [Config::BlockNumberProvider]. + /// + /// Rounds the previous block number up to the next multiple of the challenge duration. + pub fn next_challenge_at() -> BlockNumberFor { + match NextChallengeAt::::get() { + Some(next) => next, + None => { + // executed once. + let now = T::BlockNumberProvider::current_block_number(); + let prev_block = now.saturating_sub(BlockNumberFor::::one()); + let challenge_period = T::ChallengePeriod::get(); + let elapsed = prev_block % challenge_period; + let next_challenge_at = prev_block + (challenge_period - elapsed); + NextChallengeAt::::put(next_challenge_at); + next_challenge_at + }, + } + } + + /// Set the next challenge rotation. + /// + /// This supposed to be called once the current challenge is executed. + fn set_next_challenge_at() { + let prev_next_challenge_at = Self::next_challenge_at(); + let next_challenge_at = prev_next_challenge_at.saturating_add(T::ChallengePeriod::get()); + NextChallengeAt::::put(next_challenge_at); + } + /// Returns true if the given `target_round` is still in its initial voting phase. fn in_progress(target_round: RoundIndex) -> bool { let round = RoundCount::::get(); diff --git a/substrate/frame/society/src/mock.rs b/substrate/frame/society/src/mock.rs index b203dc981769e..de3fb151d8d88 100644 --- a/substrate/frame/society/src/mock.rs +++ b/substrate/frame/society/src/mock.rs @@ -48,6 +48,7 @@ parameter_types! { ord_parameter_types! { pub const ChallengePeriod: u64 = 8; pub const ClaimPeriod: u64 = 1; + pub const VotingPeriod: u64 = 3; pub const FounderSetAccount: u128 = 1; pub const SuspensionJudgementSetAccount: u128 = 2; pub const MaxPayouts: u32 = 10; @@ -75,7 +76,7 @@ impl Config for Test { type Randomness = TestRandomness; type GraceStrikes = ConstU32<1>; type PeriodSpend = ConstU64<1000>; - type VotingPeriod = ConstU64<3>; + type VotingPeriod = VotingPeriod; type ClaimPeriod = ClaimPeriod; type MaxLockDuration = ConstU64<100>; type FounderSetOrigin = EnsureSignedBy; @@ -231,6 +232,7 @@ pub fn next_intake() { ), Period::Claim { more, .. } => System::run_to_block::(System::block_number() + more), + Period::Intake { .. } => {}, } } diff --git a/substrate/frame/society/src/tests.rs b/substrate/frame/society/src/tests.rs index 82ba054501874..d559f6d9c01f7 100644 --- a/substrate/frame/society/src/tests.rs +++ b/substrate/frame/society/src/tests.rs @@ -1469,3 +1469,194 @@ fn poke_deposit_handles_insufficient_balance() { ); }); } + +#[test] +fn challenge_with_non_consecutive_blocks_works() { + EnvBuilder::new().execute(|| { + let challenge_period: u64 = ::ChallengePeriod::get(); + let now = challenge_period + 1; + let next_challenge_at = challenge_period + challenge_period; + ::BlockNumberProvider::set_block_number(now); + + assert_eq!(Society::next_challenge_at(), next_challenge_at); + + Society::on_initialize(0); + + // Add some members + place_members([20, 30, 40, 50]); + // Votes are empty + assert_eq!(DefenderVotes::::get(0, 20), None); + assert_eq!(DefenderVotes::::get(0, 30), None); + assert_eq!(DefenderVotes::::get(0, 40), None); + assert_eq!(DefenderVotes::::get(0, 50), None); + // Check starting point + assert_eq!(members(), vec![10, 20, 30, 40, 50]); + assert_eq!(Defending::::get(), None); + + // early for challenge + let now = next_challenge_at - 1; + ::BlockNumberProvider::set_block_number(now); + Society::on_initialize(0); + assert_eq!(members(), vec![10, 20, 30, 40, 50]); + assert_eq!(Defending::::get(), None); + + // challenge with delay + let now = next_challenge_at + 2; + ::BlockNumberProvider::set_block_number(now); + Society::on_initialize(0); + assert_eq!(Defending::::get().unwrap().0, 40); + // They can always free vote for themselves + assert_ok!(Society::defender_vote(Origin::signed(40), false)); + // everyone votes against 40 + assert_ok!(Society::defender_vote(Origin::signed(20), false)); + assert_ok!(Society::defender_vote(Origin::signed(30), false)); + assert_ok!(Society::defender_vote(Origin::signed(50), false)); + + let next_challenge_at = next_challenge_at + challenge_period; + assert_eq!(Society::next_challenge_at(), next_challenge_at); + + // early for challenge + let now = next_challenge_at - 2; + ::BlockNumberProvider::set_block_number(now); + Society::on_initialize(0); + assert_eq!(members(), vec![10, 20, 30, 40, 50]); + + // challenge with delay + let now = next_challenge_at - 1; + ::BlockNumberProvider::set_block_number(now); + Society::on_initialize(0); + assert_eq!(members(), vec![10, 20, 30, 40, 50]); + + // challenge without delay + let now = next_challenge_at; + ::BlockNumberProvider::set_block_number(now); + Society::on_initialize(0); + // 40 is suspended + assert_eq!(members(), vec![10, 20, 30, 50]); + assert_eq!( + SuspendedMembers::::get(40), + Some(MemberRecord { rank: 0, strikes: 0, vouching: None, index: 3 }) + ); + // Reset votes for last challenge + assert_ok!(Society::cleanup_challenge(Origin::signed(0), 0, 10)); + // New defender is chosen, 30 is challenged + assert_eq!(Defending::::get().unwrap().0, 30); + // Votes are reset + assert_eq!(DefenderVotes::::get(0, 20), None); + assert_eq!(DefenderVotes::::get(0, 30), None); + assert_eq!(DefenderVotes::::get(0, 40), None); + assert_eq!(DefenderVotes::::get(0, 50), None); + }); +} + +#[test] +fn intake_with_non_consecutive_blocks_works() { + EnvBuilder::new().execute(|| { + let voting_period: u64 = ::VotingPeriod::get(); + let claim_period: u64 = ::ClaimPeriod::get(); + let rotation_period = voting_period + claim_period; + let now = rotation_period + 1; + let next_intake_at = rotation_period + rotation_period; + ::BlockNumberProvider::set_block_number(now); + + assert_eq!(Society::next_intake_at(), next_intake_at); + assert_eq!(Society::period(), Period::Voting { elapsed: 1, more: 2 }); + + Society::on_initialize(0); + + assert_eq!(Balances::free_balance(20), 50); + // Bid causes Candidate Deposit to be reserved. + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); + assert_eq!(Balances::free_balance(20), 25); + + // early for intake + let now = next_intake_at - 1; + ::BlockNumberProvider::set_block_number(now); + assert_eq!(Society::period(), Period::Claim { elapsed: 0, more: 1 }); + Society::on_initialize(0); + assert_eq!(candidacies(), vec![]); + + // intake with delay + let now = next_intake_at + 1; + ::BlockNumberProvider::set_block_number(now); + assert_eq!(Society::period(), Period::Intake { elapsed: 1 }); + Society::on_initialize(0); + // 20 is now a candidate + assert_eq!(candidacies(), vec![(20, candidacy(1, 0, Deposit(25), 0, 0))]); + // 10 (a member) can vote for the candidate + assert_ok!(Society::vote(Origin::signed(10), 20, true)); + conclude_intake(true, None); + + let next_intake_at = next_intake_at + rotation_period; + assert_eq!(Society::next_intake_at(), next_intake_at); + + // intake without delay + let now = next_intake_at; + ::BlockNumberProvider::set_block_number(now); + assert_eq!(Society::period(), Period::Intake { elapsed: 0 }); + Society::on_initialize(0); + // 20 is now a member of the society + assert_eq!(members(), vec![10, 20]); + // Reserved balance is returned + assert_eq!(Balances::free_balance(20), 50); + }); +} + +#[test] +fn intake_idempotency() { + EnvBuilder::new().execute(|| { + let voting_period: u64 = ::VotingPeriod::get(); + let claim_period: u64 = ::ClaimPeriod::get(); + let rotation_period = voting_period + claim_period; + let now = rotation_period + 1; + let next_intake_at = rotation_period + rotation_period; + ::BlockNumberProvider::set_block_number(now); + + assert_eq!(Society::next_intake_at(), next_intake_at); + assert_eq!(Society::period(), Period::Voting { elapsed: 1, more: 2 }); + + // initialize the next intake at + Society::on_initialize(0); + + // Bid to become a candidate + assert_eq!(Balances::free_balance(20), 50); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); + + // intake + let now = next_intake_at; + ::BlockNumberProvider::set_block_number(now); + assert_eq!(Society::period(), Period::Intake { elapsed: 0 }); + Society::on_initialize(0); + // 20 is now a candidate + assert_eq!(candidacies(), vec![(20, candidacy(1, 0, Deposit(25), 0, 0))]); + + // Bid one more account to become a candidate + assert_eq!(Balances::free_balance(40), 50); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 10)); + + // next intake has updated + let next_intake_at = next_intake_at + rotation_period; + assert_eq!(Society::next_intake_at(), next_intake_at); + + // `on_initialize` at the same block provider block number has not effect + assert_eq!(Society::period(), Period::Voting { elapsed: 0, more: 3 }); + Society::on_initialize(0); + // 20 is still the only candidate + assert_eq!(candidacies(), vec![(20, candidacy(1, 0, Deposit(25), 0, 0))]); + + // 10 (a member) can vote for the candidate + assert_ok!(Society::vote(Origin::signed(10), 20, true)); + // moves the block to the Claim period + conclude_intake(true, None); + + // next intake adds the candidate to the society + let now = next_intake_at; + ::BlockNumberProvider::set_block_number(now); + assert_eq!(Society::period(), Period::Intake { elapsed: 0 }); + Society::on_initialize(0); + // 20 is now a member of the society + assert_eq!(members(), vec![10, 20]); + // Reserved balance is returned + assert_eq!(Balances::free_balance(20), 50); + }); +} From 9e0b6dd0f6fc7c877ffeb9b53d293fb8a5e177d2 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Tue, 26 Aug 2025 12:00:48 +0200 Subject: [PATCH 16/16] bump subxt --- Cargo.lock | 22 ++++++++++++---------- Cargo.toml | 6 +++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1378f1767f018..ffc452d440738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6739,8 +6739,8 @@ dependencies = [ "sp-version", "sp-wasm-interface 20.0.0", "substrate-test-runtime", - "subxt 0.41.0", - "subxt-signer 0.41.0", + "subxt 0.43.0", + "subxt-signer 0.43.0", "thiserror 1.0.69", "thousands", "westend-runtime", @@ -13217,7 +13217,7 @@ dependencies = [ "sp-runtime", "sp-tracing 16.0.0", "substrate-bn", - "subxt-signer 0.41.0", + "subxt-signer 0.43.0", ] [[package]] @@ -13252,8 +13252,8 @@ dependencies = [ "static_init", "substrate-cli-test-utils", "substrate-prometheus-endpoint", - "subxt 0.41.0", - "subxt-signer 0.41.0", + "subxt 0.43.0", + "subxt-signer 0.43.0", "thiserror 1.0.69", "tokio", ] @@ -16054,7 +16054,7 @@ dependencies = [ "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", - "subxt-metadata 0.41.0", + "subxt-metadata 0.43.0", "tokio", "wait-timeout", ] @@ -20776,7 +20776,7 @@ dependencies = [ "sp-state-machine", "sp-version", "sp-wasm-interface 20.0.0", - "subxt 0.41.0", + "subxt 0.43.0", "thiserror 1.0.69", ] @@ -24420,7 +24420,7 @@ dependencies = [ "sp-keyring", "staging-node-inspect", "substrate-cli-test-utils", - "subxt-signer 0.41.0", + "subxt-signer 0.43.0", "tempfile", "tokio", "tokio-util", @@ -25412,7 +25412,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ba7494d250d65dc3439365ac5e8e0fbb9c3992e6e84b7aa01d69e082249b8b8" dependencies = [ "derive-where", - "finito", "frame-metadata 20.0.0", "futures", "hex", @@ -25425,7 +25424,6 @@ dependencies = [ "subxt-core 0.41.0", "subxt-lightclient 0.41.0", "thiserror 2.0.16", - "tokio", "tokio-util", "tracing", "url", @@ -25438,6 +25436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25de7727144780d780a6a7d78bbfd28414b8adbab68b05e87329c367d7705be4" dependencies = [ "derive-where", + "finito", "frame-metadata 23.0.0", "futures", "hex", @@ -25450,6 +25449,7 @@ dependencies = [ "subxt-core 0.43.0", "subxt-lightclient 0.43.0", "thiserror 2.0.16", + "tokio", "tokio-util", "tracing", "url", @@ -25492,11 +25492,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a9bd240ae819f64ac6898d7ec99a88c8b838dba2fb9d83b843feb70e77e34c8" dependencies = [ "base64 0.22.1", + "bip32", "bip39", "cfg-if", "crypto_secretbox", "hex", "hmac 0.12.1", + "keccak-hash", "parity-scale-codec", "pbkdf2", "regex", diff --git a/Cargo.toml b/Cargo.toml index 76e9822ad23f8..f177f6f5b6383 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1401,9 +1401,9 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -subxt = { version = "0.41", default-features = false } -subxt-metadata = { version = "0.41", default-features = false } -subxt-signer = { version = "0.41" } +subxt = { version = "0.43", default-features = false } +subxt-metadata = { version = "0.43", default-features = false } +subxt-signer = { version = "0.43" } syn = { version = "2.0.87" } sysinfo = { version = "0.30" } tar = { version = "0.4" }