diff --git a/Cargo.lock b/Cargo.lock index c52ec8dc6..e6f1982b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2129,7 +2129,7 @@ dependencies = [ "byteorder", "bytes", "fluentbase-codec-derive", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hex", "hex-literal 1.0.0", "serde", @@ -2210,7 +2210,6 @@ dependencies = [ "solana-bn254", "solana-curve25519", "solana-poseidon", - "solana-program-option", "solana-program-pack", "wat", ] @@ -2226,6 +2225,7 @@ dependencies = [ "revm-rwasm-context", "revm-rwasm-interpreter", "revm-rwasm-primitives", + "serde", ] [[package]] @@ -2295,9 +2295,10 @@ dependencies = [ "fluentbase-crypto", "fluentbase-sdk-derive", "fluentbase-types", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hex-literal 1.0.0", "rwasm", + "spin 0.10.0", ] [[package]] @@ -2356,7 +2357,7 @@ dependencies = [ "fluentbase-svm-common", "fluentbase-testing", "fluentbase-universal-token", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "itertools 0.14.0", "lazy_static", "memoffset", @@ -2427,7 +2428,7 @@ dependencies = [ "fluentbase-revm", "fluentbase-runtime", "fluentbase-sdk", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hex", "revm-rwasm", "rwasm", @@ -2440,7 +2441,9 @@ dependencies = [ "alloy-primitives", "bincode 2.0.1", "byteorder", - "hashbrown 0.15.5", + "fluentbase-codec", + "fluentbase-codec-derive", + "hashbrown 0.16.0", "paste", "revm-rwasm-precompile", "revm-rwasm-primitives", diff --git a/Cargo.toml b/Cargo.toml index adae1d40b..8194bffd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ solana_rbpf = { git = "https://github.com/fluentlabs-xyz/rbpf", branch = "feat/s # rwasm rwasm = { version = "0.3.2", default-features = false } #rwasm = { path = "../rwasm", default-features = false } +#rwasm = { path = "../rwasm", default-features = false } # alloy alloy-primitives = { version = "1.2.0", default-features = false, features = ["sha3-keccak"] } @@ -120,7 +121,7 @@ proptest = { version = "1.5.0" } num-derive = { version = "0.4" } num-traits = { version = "0.2", features = ["i128"], default-features = false } -hashbrown = { version = "0.15.0", default-features = false, features = ["default-hasher", "inline-more"] } +hashbrown = { version = "0.16.0", default-features = false, features = ["default-hasher", "inline-more"] } schnellru = { version = "0.2" } serde = { version = "1.0.203", default-features = false, features = ["derive", "rc"] } serde_json = { version = "1.0", default-features = false } @@ -148,12 +149,12 @@ elliptic-curve = { version = "0.13.4", features = ["hazmat", "sec1", "ecdh"], de cfg-if = { version = "1.0.3", default-features = false } # revm -revm = { package="revm-rwasm", version = "27.0.3", default-features = false } -revm-primitives = { package="revm-rwasm-primitives", version = "20.0.0", default-features = false } -revm-precompile = { package="revm-rwasm-precompile", version = "24.0.1", default-features = false } -revm-bytecode = { package="revm-rwasm-bytecode", version = "6.0.1", default-features = false } -revm-interpreter = { package="revm-rwasm-interpreter", version = "23.0.2", default-features = false } -revm-context = { package="revm-rwasm-context", version = "8.0.3", default-features = false } +revm = { package = "revm-rwasm", version = "27.0.3", default-features = false } +revm-primitives = { package = "revm-rwasm-primitives", version = "20.0.0", default-features = false } +revm-precompile = { package = "revm-rwasm-precompile", version = "24.0.1", default-features = false } +revm-bytecode = { package = "revm-rwasm-bytecode", version = "6.0.1", default-features = false } +revm-interpreter = { package = "revm-rwasm-interpreter", version = "23.0.2", default-features = false } +revm-context = { package = "revm-rwasm-context", version = "8.0.3", default-features = false } #revm = { path = "../revm-rwasm/crates/revm", default-features = false } #revm-primitives = { path = "../revm-rwasm/crates/primitives", default-features = false } #revm-precompile = { path = "../revm-rwasm/crates/precompile", default-features = false } diff --git a/contracts/.cargo/config.toml b/contracts/.cargo/config.toml index 5d6d5d433..dfdcbdc4d 100644 --- a/contracts/.cargo/config.toml +++ b/contracts/.cargo/config.toml @@ -1,2 +1,13 @@ [build] +# Default build target triple +target = "wasm32-unknown-unknown" + +# Directory for all build artifacts target-dir = "../target/contracts" + +# Global rustflags +rustflags = [ + "-C", "link-arg=-zstack-size=1048576", + "-C", "target-feature=+bulk-memory", + "-C", "target-feature=+tail-call", +] \ No newline at end of file diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 8539e236e..0e5cf775e 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -29,7 +29,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2acb6637a9c0e1cdf8971e0ced8f3fa34c04c5e9dccf6bb184f6a64fe0e37d8" +checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b77f7d5e60ad8ae6bd2200b8097919712a07a6db622a4b201e7ead6166f02e5" +checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", @@ -123,14 +123,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "alloy-sol-macro-input" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5772107f9bb265d8d8c86e0733937bb20d0857ea5425b1b6ddf51a9804042" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "alloy-json-abi", "const-hex", @@ -140,15 +140,15 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e188b939aa4793edfaaa099cb1be4e620036a775b4bdf24fdc56f1cd6fd45890" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", "winnow", @@ -160,6 +160,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object 0.32.2", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -296,7 +305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -334,7 +343,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -423,7 +432,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -482,7 +491,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -503,7 +512,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -604,11 +613,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -652,7 +661,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -661,7 +670,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -741,7 +750,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -776,9 +785,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.40" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "jobserver", @@ -872,9 +881,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6407bff74dea37e0fa3dc1c1c974e5d46405f0c987bf9997a0762adce71eda6" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", "cpufeatures", @@ -890,9 +899,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -1149,7 +1158,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", "rand_core 0.6.4", "subtle", "zeroize", @@ -1161,7 +1170,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", "typenum", ] @@ -1211,7 +1220,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1235,7 +1244,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1246,7 +1255,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1357,14 +1366,14 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -1388,7 +1397,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1417,7 +1426,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1428,7 +1437,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "unicode-xid", ] @@ -1438,7 +1447,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -1509,7 +1518,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1528,7 +1537,7 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array 0.14.7", + "generic-array 0.14.9", "group", "hkdf", "pem-rfc7468", @@ -1562,22 +1571,22 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1593,7 +1602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1671,9 +1680,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "five8_const" @@ -1716,7 +1725,7 @@ dependencies = [ "byteorder", "bytes", "fluentbase-codec-derive", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", ] @@ -1729,7 +1738,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1787,6 +1796,7 @@ dependencies = [ "fluentbase-evm", "fluentbase-sdk", "fluentbase-testing", + "spin 0.10.0", ] [[package]] @@ -1929,6 +1939,7 @@ dependencies = [ "revm-rwasm-context", "revm-rwasm-interpreter", "revm-rwasm-primitives", + "serde", ] [[package]] @@ -1949,6 +1960,7 @@ dependencies = [ name = "fluentbase-runtime" version = "0.4.11-dev" dependencies = [ + "anyhow", "blake3", "bytemuck", "fluentbase-types", @@ -1958,10 +1970,12 @@ dependencies = [ "rwasm", "schnellru", "sha2 0.10.9", + "smallvec", "snowbridge-amcl", "solana-poseidon", "sp1-curves", "tiny-keccak", + "wasmtime-rwasm", ] [[package]] @@ -1975,8 +1989,9 @@ dependencies = [ "fluentbase-crypto", "fluentbase-sdk-derive", "fluentbase-types", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "rwasm", + "spin 0.10.0", ] [[package]] @@ -1989,7 +2004,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2008,7 +2023,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", "thiserror 2.0.17", "tracing", @@ -2028,7 +2043,7 @@ dependencies = [ "fluentbase-sdk", "fluentbase-svm-common", "fluentbase-universal-token 0.4.11-dev", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "itertools 0.14.0", "lazy_static", "num-derive", @@ -2086,7 +2101,7 @@ dependencies = [ "fluentbase-revm", "fluentbase-runtime", "fluentbase-sdk", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hex", "revm-rwasm", "rwasm", @@ -2099,11 +2114,14 @@ dependencies = [ "alloy-primitives", "bincode 2.0.1", "byteorder", - "hashbrown 0.15.5", + "fluentbase-codec", + "fluentbase-codec-derive", + "hashbrown 0.16.0", "paste", "revm-rwasm-precompile", "revm-rwasm-primitives", "rwasm", + "serde", "strum_macros 0.27.2", ] @@ -2185,9 +2203,9 @@ checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2230,14 +2248,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] [[package]] @@ -2309,12 +2327,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -2446,14 +2465,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -2535,15 +2554,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -2623,9 +2642,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" @@ -2784,7 +2803,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2912,7 +2931,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2983,9 +3002,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2993,14 +3012,23 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", ] [[package]] @@ -3304,7 +3332,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3385,7 +3413,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3488,7 +3516,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit 0.23.7", ] [[package]] @@ -3516,23 +3544,22 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", "bitflags", - "lazy_static", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -3545,10 +3572,11 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66fcd288453b748497d8fb18bccc83a16b0518e3906d4b8df0a8d42d93dbb1c" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" dependencies = [ + "ar_archive_writer", "cc", ] @@ -3572,7 +3600,7 @@ checksum = "9276d404009cc49f3b8befeb8ffc1d868c5ea732bd9d72ab3e64231187f908c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3691,7 +3719,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "serde", ] @@ -3778,9 +3806,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "revm-precompile" @@ -4130,7 +4158,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4201,7 +4229,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4238,7 +4266,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4249,7 +4277,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array 0.14.9", "pkcs8", "subtle", "zeroize", @@ -4349,7 +4377,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4376,9 +4404,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", @@ -4841,7 +4869,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4960,9 +4988,9 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69234f4667ae1a00f7bfb90b42d6aa141744114b128ac262b9a28e9c869cf514" +checksum = "3e29cb79716167e58c0719d572e686880172f1816cd85e0acab74ea0ff3c795e" dependencies = [ "cfg-if", "dashu", @@ -4982,9 +5010,9 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a736bce661752b1d6ecf33eca197443fb535124b3caabd332862d6f8258e3c8d" +checksum = "7ac59616976c008e862f99d26fd0c1c037d464df33d9ca548be88f938f0b1bcf" dependencies = [ "quote", "syn 1.0.109", @@ -4992,9 +5020,9 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1fe81b6f87134f9170cb642f948ae41e0ee1cd3785e0cb665add5b67106d1a" +checksum = "fce8ad0f153443d09d398eccb650a0b2dcbf829470e394e4bf60ec4379c7af93" dependencies = [ "bincode 1.3.3", "serde", @@ -5003,9 +5031,9 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dddd8d022840c1c500e0d7f82e9b9cf080b7dabd469f06b394010e6a594f692b" +checksum = "0244dee3a7a0f88cf71c3edf518f4fc97794ae870a107cbe7c810ac3fbf879cb" dependencies = [ "bincode 1.3.3", "blake3", @@ -5023,9 +5051,9 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48b9b57606ab0eb9560f0456dc978166ab0a3bd9d8b3f2ab24ea5e1377c56f07" +checksum = "1f0cdde80366245a374d29fecdde2881286002a6e3f51b84f54b86560ed026e5" dependencies = [ "arrayref", "hashbrown 0.14.5", @@ -5051,7 +5079,6 @@ dependencies = [ "sp1-derive", "sp1-primitives", "strum", - "strum_macros 0.26.4", "sysinfo", "tracing", ] @@ -5101,9 +5128,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -5131,6 +5158,9 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] [[package]] name = "strum_macros" @@ -5142,7 +5172,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5154,7 +5184,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5176,9 +5206,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -5187,14 +5217,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2375c17f6067adc651d8c2c51658019cef32edfff4a982adaf1d7fd1c039f08b" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5231,10 +5261,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5272,7 +5302,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5283,7 +5313,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5361,9 +5391,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] @@ -5384,21 +5414,21 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ "indexmap", - "toml_datetime 0.7.2", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -5428,7 +5458,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5458,7 +5488,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5505,9 +5535,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -5517,9 +5547,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -5597,15 +5627,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -5617,9 +5638,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -5628,25 +5649,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5654,22 +5661,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -5686,12 +5693,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" +checksum = "06d642d8c5ecc083aafe9ceb32809276a304547a3a6eeecceb5d8152598bc71f" dependencies = [ "leb128fmt", - "wasmparser 0.239.0", + "wasmparser 0.240.0", ] [[package]] @@ -5758,9 +5765,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ "bitflags", "indexmap", @@ -5825,7 +5832,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -5853,7 +5860,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "smallvec", "target-lexicon", "thiserror 2.0.17", @@ -5876,7 +5883,7 @@ dependencies = [ "gimli", "indexmap", "log", - "object", + "object 0.36.7", "postcard", "rustc-demangle", "semver 1.0.27", @@ -5913,7 +5920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d83fa2dea686f76b5437b66045aae6351d359ee11cc4124f9842de63837b81" dependencies = [ "cc", - "object", + "object 0.36.7", "rustix", "wasmtime-versioned-export-macros", ] @@ -5962,7 +5969,7 @@ dependencies = [ "log", "mach2", "memfd", - "object", + "object 0.36.7", "once_cell", "postcard", "psm", @@ -6011,7 +6018,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "pulley-interpreter", "smallvec", "target-lexicon", @@ -6036,7 +6043,7 @@ checksum = "4e052e1d9c30b8f31aff64380caaaff492a9890a412658bcc8866fe626b8e91f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6048,7 +6055,7 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object", + "object 0.36.7", "target-lexicon", "wasmparser 0.233.0", "wasmtime-cranelift", @@ -6070,31 +6077,31 @@ dependencies = [ [[package]] name = "wast" -version = "239.0.0" +version = "240.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" +checksum = "b0efe1c93db4ac562b9733e3dca19ed7fc878dba29aef22245acf84f13da4a19" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.239.0", + "wasm-encoder 0.240.0", ] [[package]] name = "wat" -version = "1.239.0" +version = "1.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" +checksum = "4ec9b6eab7ecd4d639d78515e9ea491c9bacf494aa5eda10823bd35992cf8c1e" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -6131,7 +6138,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6181,9 +6188,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -6200,7 +6207,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -6221,19 +6237,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 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", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -6244,9 +6260,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -6256,9 +6272,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -6268,9 +6284,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -6280,9 +6296,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -6292,9 +6308,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -6304,9 +6320,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -6316,9 +6332,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -6328,9 +6344,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -6402,7 +6418,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6422,7 +6438,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] diff --git a/contracts/blake2f/lib.rs b/contracts/blake2f/lib.rs index 99d8d22e0..c8b1a16aa 100644 --- a/contracts/blake2f/lib.rs +++ b/contracts/blake2f/lib.rs @@ -2,24 +2,21 @@ extern crate alloc; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; +use fluentbase_sdk::{system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; -pub fn main_entry(mut sdk: impl SharedAPI) { +pub fn main_entry(sdk: &mut impl SharedAPI) -> Result { // read full input data let gas_limit = sdk.context().contract_gas_limit(); - let input_length = sdk.input_size(); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); - let input = Bytes::copy_from_slice(input); + let input = sdk.input(); // call blake2 function - let result = revm_precompile::blake2::run(&input, gas_limit) - .unwrap_or_else(|_| sdk.native_exit(ExitCode::PrecompileError)); - sdk.sync_evm_gas(result.gas_used); + let result = + revm_precompile::blake2::run(&input, gas_limit).map_err(|_| ExitCode::PrecompileError)?; + sdk.sync_evm_gas(result.gas_used)?; // write output - sdk.write(result.bytes.as_ref()); + Ok(result.bytes) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -29,16 +26,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 10_000_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/bls12381/lib.rs b/contracts/bls12381/lib.rs index 2bfa58363..f0e083b55 100644 --- a/contracts/bls12381/lib.rs +++ b/contracts/bls12381/lib.rs @@ -1,12 +1,12 @@ #![cfg_attr(target_arch = "wasm32", no_std, no_main)] extern crate alloc; +use alloc::vec::Vec; use bls12_381::{pairing, G1Affine, G1Projective, G2Affine, G2Projective, Gt, Scalar}; use fluentbase_sdk::{ - alloc_slice, entrypoint, Bytes, ContextReader, ExitCode, SharedAPI, - PRECOMPILE_BLS12_381_G1_ADD, PRECOMPILE_BLS12_381_G1_MSM, PRECOMPILE_BLS12_381_G2_ADD, - PRECOMPILE_BLS12_381_G2_MSM, PRECOMPILE_BLS12_381_MAP_G1, PRECOMPILE_BLS12_381_MAP_G2, - PRECOMPILE_BLS12_381_PAIRING, + system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI, PRECOMPILE_BLS12_381_G1_ADD, + PRECOMPILE_BLS12_381_G1_MSM, PRECOMPILE_BLS12_381_G2_ADD, PRECOMPILE_BLS12_381_G2_MSM, + PRECOMPILE_BLS12_381_MAP_G1, PRECOMPILE_BLS12_381_MAP_G2, PRECOMPILE_BLS12_381_PAIRING, }; use revm_precompile::bls12_381::{ g2_msm::g2_msm, map_fp2_to_g2::map_fp2_to_g2, map_fp_to_g1::map_fp_to_g1, @@ -98,17 +98,24 @@ fn msm_required_gas(k: usize, discount_table: &[u16], multiplication_cost: u64) } #[inline(always)] -fn check_gas_and_sync(sdk: &SDK, gas_used: u64, gas_limit: u64) { +fn check_gas_and_sync( + sdk: &SDK, + gas_used: u64, + gas_limit: u64, +) -> Result<(), ExitCode> { if gas_used > gas_limit { - sdk.native_exit(ExitCode::OutOfFuel); + return Err(ExitCode::OutOfFuel); } - sdk.sync_evm_gas(gas_used); + sdk.sync_evm_gas(gas_used)?; + Ok(()) } #[inline(always)] -fn validate_input_length(sdk: &SDK, actual: u32, expected: usize) { +fn validate_input_length(actual: u32, expected: usize) -> Result<(), ExitCode> { if actual != expected as u32 { - sdk.native_exit(ExitCode::InputOutputOutOfBounds); + Err(ExitCode::InputOutputOutOfBounds) + } else { + Ok(()) } } @@ -301,30 +308,29 @@ fn validate_and_consume_gas( expected_length: usize, gas_cost: u64, gas_limit: u64, -) { - validate_input_length(sdk, input_length, expected_length); - check_gas_and_sync(sdk, gas_cost, gas_limit); +) -> Result<(), ExitCode> { + validate_input_length(input_length, expected_length)?; + check_gas_and_sync(sdk, gas_cost, gas_limit)?; + Ok(()) } -pub fn main_entry(mut sdk: SDK) { +pub fn main_entry(sdk: &mut SDK) -> Result { // read full input data let bytecode_address = sdk.context().contract_bytecode_address(); let gas_limit = sdk.context().contract_gas_limit(); let input_length = sdk.input_size(); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); - let input = Bytes::copy_from_slice(input); + let input = sdk.input(); // dispatch to SDK-backed implementation match bytecode_address { PRECOMPILE_BLS12_381_G1_ADD => { // Expect two G1 points (x1||y1||x2||y2), each coord 64 bytes BE padded validate_and_consume_gas( - &sdk, + sdk, input_length, G1_ADD_INPUT_LENGTH, G1_ADD_GAS, gas_limit, - ); + )?; // Convert input from EVM format to runtime format let (p, q) = convert_g1_input_to_runtime(&input); // Use rWASM-patched bls12_381 directly for optimized execution @@ -336,17 +342,17 @@ pub fn main_entry(mut sdk: SDK) { // Convert output from runtime format to EVM format let out = convert_g1_output_to_evm(&result_bytes); - sdk.write(&out); + Ok(out.into()) } PRECOMPILE_BLS12_381_G2_ADD => { // EIP-2537: input must be 512 bytes (two G2 elements, each 256 bytes padded) validate_and_consume_gas( - &sdk, + sdk, input_length, G2_ADD_INPUT_LENGTH, G2_ADD_GAS, gas_limit, - ); + )?; // Convert input from EVM format to runtime format let (p, q) = convert_g2_input_to_rwasm_patches(&input); @@ -360,25 +366,24 @@ pub fn main_entry(mut sdk: SDK) { // Encode output: 256 bytes (x0||x1||y0||y1), each limb is 64-byte BE padded (16 zeros + 48 value) let out = convert_g2_output_to_evm_rwasm(&result_bytes); - sdk.write(&out); + Ok(out.into()) } PRECOMPILE_BLS12_381_G1_MSM => { // Expect pairs of 160 bytes: 128-byte padded G1 point (x||y) + 32-byte scalar (BE) // Convert to rwasm-patches format: 96-byte uncompressed G1 + Scalar let input_length_requirement = G1_MSM_INPUT_LENGTH; if input.len() % input_length_requirement != 0 || input.is_empty() { - sdk.native_exit(ExitCode::InputOutputOutOfBounds); + return Err(ExitCode::InputOutputOutOfBounds); } let pairs_len = input.len() / input_length_requirement; // We check for the gas in the very beginning to reduce execution time let gas_used = msm_required_gas(pairs_len, &DISCOUNT_TABLE_G1_MSM, G1_MSM_GAS); - check_gas_and_sync(&sdk, gas_used, gas_limit); + check_gas_and_sync(sdk, gas_used, gas_limit)?; // Collect G1 points and scalars for MSM - let mut points: alloc::vec::Vec = - alloc::vec::Vec::with_capacity(pairs_len); - let mut scalars: alloc::vec::Vec = alloc::vec::Vec::with_capacity(pairs_len); + let mut points: Vec = Vec::with_capacity(pairs_len); + let mut scalars: Vec = Vec::with_capacity(pairs_len); for i in 0..pairs_len { let start = i * input_length_requirement; @@ -404,29 +409,23 @@ pub fn main_entry(mut sdk: SDK) { let result_aff = G1Affine::from(result); let result_bytes = result_aff.to_uncompressed(); - // Check if result is identity - if result_aff.is_identity().unwrap_u8() == 1 { - let out = [0u8; PADDED_G1_SIZE]; - sdk.write(&out); + // Check if the result is identity + let out = if result_aff.is_identity().unwrap_u8() == 1 { + [0u8; PADDED_G1_SIZE] } else { - // Convert result to EVM format - let out = convert_g1_output_to_evm(&result_bytes); - sdk.write(&out); - } + convert_g1_output_to_evm(&result_bytes) + }; + Ok(out.into()) } PRECOMPILE_BLS12_381_G2_MSM => { - match g2_msm(&input, gas_limit) { - Ok(output) => { - // Consume the gas that was used by the precompile - sdk.sync_evm_gas(output.gas_used); - sdk.write(&output.bytes); - } - Err(_) => sdk.native_exit(ExitCode::InputOutputOutOfBounds), - } + let output = g2_msm(&input, gas_limit).map_err(|_| ExitCode::InputOutputOutOfBounds)?; + // Consume the gas that was used by to precompile + sdk.sync_evm_gas(output.gas_used)?; + Ok(output.bytes) } PRECOMPILE_BLS12_381_PAIRING => { if input.is_empty() || input.len() % PAIRING_INPUT_LENGTH != 0 { - sdk.native_exit(ExitCode::InputOutputOutOfBounds); + return Err(ExitCode::InputOutputOutOfBounds); } let pairs_len = input.len() / PAIRING_INPUT_LENGTH; // Gas: PAIRING_MULTIPLIER_BASE * pairs + PAIRING_OFFSET_BASE @@ -434,9 +433,9 @@ pub fn main_entry(mut sdk: SDK) { .saturating_mul(pairs_len as u64) .saturating_add(PAIRING_OFFSET_BASE); if required_gas > gas_limit { - sdk.native_exit(ExitCode::OutOfFuel); + return Err(ExitCode::OutOfFuel); } - sdk.sync_evm_gas(required_gas); + sdk.sync_evm_gas(required_gas)?; // Process each pair and compute the product of all pairings let mut result = Gt::identity(); @@ -469,35 +468,29 @@ pub fn main_entry(mut sdk: SDK) { if is_one { out_be[31] = 1; } - sdk.write(&out_be); + Ok(out_be.into()) } PRECOMPILE_BLS12_381_MAP_G1 => { // Use revm_precompile directly for MAP_G1 - match map_fp_to_g1(&input, gas_limit) { - Ok(output) => { - // Consume the gas that was used by the precompile - sdk.sync_evm_gas(output.gas_used); - sdk.write(&output.bytes); - } - Err(_) => sdk.native_exit(ExitCode::InputOutputOutOfBounds), - } + let output = + map_fp_to_g1(&input, gas_limit).map_err(|_| ExitCode::InputOutputOutOfBounds)?; + // Consume the gas that was used by to precompile + sdk.sync_evm_gas(output.gas_used)?; + Ok(output.bytes) } PRECOMPILE_BLS12_381_MAP_G2 => { // Use revm_precompile directly for MAP_G2 - match map_fp2_to_g2(&input, gas_limit) { - Ok(output) => { - // Consume the gas that was used by the precompile - sdk.sync_evm_gas(output.gas_used); - sdk.write(&output.bytes); - } - Err(_) => sdk.native_exit(ExitCode::InputOutputOutOfBounds), - } + let output = + map_fp2_to_g2(&input, gas_limit).map_err(|_| ExitCode::InputOutputOutOfBounds)?; + // Consume the gas that was used by to precompile + sdk.sync_evm_gas(output.gas_used)?; + Ok(output.bytes) } _ => unreachable!("bls12381: unsupported contract address"), } } -entrypoint!(main_entry); +system_entrypoint!(main_entry); /** * The following are the tests for the BLS12-381 precompile contract. @@ -513,7 +506,7 @@ mod tests { fn exec_evm_precompile(address: Address, inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 120_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { address, @@ -522,9 +515,8 @@ mod tests { ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/bn256/lib.rs b/contracts/bn256/lib.rs index ccffa5327..3a0da83ae 100644 --- a/contracts/bn256/lib.rs +++ b/contracts/bn256/lib.rs @@ -4,8 +4,9 @@ extern crate core; extern crate fluentbase_sdk; use fluentbase_sdk::{ - alloc_slice, crypto::CryptoRuntime, entrypoint, ContextReader, CryptoAPI, ExitCode, SharedAPI, - BN254_G1_RAW_AFFINE_SIZE, PRECOMPILE_BN256_ADD, PRECOMPILE_BN256_MUL, PRECOMPILE_BN256_PAIR, + alloc_slice, crypto::CryptoRuntime, system_entrypoint, Bytes, ContextReader, CryptoAPI, + ExitCode, SharedAPI, BN254_G1_RAW_AFFINE_SIZE, PRECOMPILE_BN256_ADD, PRECOMPILE_BN256_MUL, + PRECOMPILE_BN256_PAIR, }; use revm_precompile::{ bn128, @@ -80,7 +81,7 @@ fn is_valid_point(point: &[u8; BN254_G1_RAW_AFFINE_SIZE]) -> bool { point.is_on_curve() && point.is_in_correct_subgroup_assuming_on_curve() } -pub fn main_entry(mut sdk: SDK) { +pub fn main_entry(sdk: &mut SDK) -> Result { let bytecode_address = sdk.context().contract_bytecode_address(); let input_length = sdk.input_size(); let mut input = alloc_slice(input_length as usize); @@ -88,7 +89,7 @@ pub fn main_entry(mut sdk: SDK) { match bytecode_address { PRECOMPILE_BN256_ADD => { - sdk.sync_evm_gas(ISTANBUL_ADD_GAS_COST); + sdk.sync_evm_gas(ISTANBUL_ADD_GAS_COST)?; // Pad input to 128 bytes (two 64-byte points) with zeros if needed let mut padded_input = [0u8; BN254_ADD_INPUT_SIZE]; @@ -104,7 +105,7 @@ pub fn main_entry(mut sdk: SDK) { // Validate both points are either identity or on the curve if !is_valid_point(&p_be) || !is_valid_point(&q_be) { // Invalid point: fail the transaction by exiting with error - sdk.native_exit(ExitCode::PrecompileError) + return Err(ExitCode::PrecompileError); } // Convert from Ethereum's big-endian to SP1's little-endian format @@ -129,33 +130,28 @@ pub fn main_entry(mut sdk: SDK) { // Convert result back to Ethereum's big-endian format point_le_to_be(&mut result); - sdk.write(&result); + Ok(result.into()) } PRECOMPILE_BN256_MUL => { - sdk.sync_evm_gas(ISTANBUL_MUL_GAS_COST); - let result = match bn128::run_mul(input, ISTANBUL_MUL_GAS_COST, u64::MAX) { - Ok(result) => result, - Err(_) => sdk.native_exit(ExitCode::PrecompileError), - }; - sdk.write(&result.bytes); + sdk.sync_evm_gas(ISTANBUL_MUL_GAS_COST)?; + let result = bn128::run_mul(input, ISTANBUL_MUL_GAS_COST, u64::MAX) + .map_err(|_| ExitCode::PrecompileError)?; + Ok(result.bytes) } PRECOMPILE_BN256_PAIR => { let gas_used = (input.len() / PAIR_ELEMENT_LEN) as u64 * ISTANBUL_PAIR_PER_POINT + ISTANBUL_PAIR_BASE; - sdk.sync_evm_gas(gas_used); + sdk.sync_evm_gas(gas_used)?; let result = - match bn128::run_pair(input, ISTANBUL_PAIR_PER_POINT, ISTANBUL_PAIR_BASE, u64::MAX) - { - Ok(result) => result, - Err(_) => sdk.native_exit(ExitCode::PrecompileError), - }; - sdk.write(&result.bytes); + bn128::run_pair(input, ISTANBUL_PAIR_PER_POINT, ISTANBUL_PAIR_BASE, u64::MAX) + .map_err(|_| ExitCode::PrecompileError)?; + Ok(result.bytes) } _ => unreachable!("bn128: unsupported contract address"), - }; + } } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -165,7 +161,7 @@ mod tests { fn exec_evm_precompile(address: Address, inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 200_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { address, @@ -174,9 +170,8 @@ mod tests { ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/ecrecover/lib.rs b/contracts/ecrecover/lib.rs index d926c2673..401db9e68 100644 --- a/contracts/ecrecover/lib.rs +++ b/contracts/ecrecover/lib.rs @@ -3,10 +3,10 @@ extern crate alloc; extern crate core; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, SharedAPI, B256, B512}; +use fluentbase_sdk::{alloc_slice, system_entrypoint, Bytes, ExitCode, SharedAPI, B256, B512}; use revm_precompile::{secp256k1::ecrecover, utilities::right_pad}; -pub fn main_entry(mut sdk: SDK) { +pub fn main_entry(sdk: &mut SDK) -> Result { // read full input data let input_length = sdk.input_size(); let mut input = alloc_slice(input_length as usize); @@ -15,13 +15,13 @@ pub fn main_entry(mut sdk: SDK) { // Make sure we have enough gas for execution const ECRECOVER_BASE: u64 = 3_000; - sdk.sync_evm_gas(ECRECOVER_BASE); + sdk.sync_evm_gas(ECRECOVER_BASE)?; let input = right_pad::<128>(input.as_ref()); // `v` must be a 32-byte big-endian integer equal to 27 or 28. if !(input[32..63].iter().all(|&b| b == 0) && matches!(input[63], 27 | 28)) { - return; + return Ok(Bytes::new()); } let msg = <&B256>::try_from(&input[0..32]).unwrap(); @@ -29,7 +29,9 @@ pub fn main_entry(mut sdk: SDK) { let sig = <&B512>::try_from(&input[64..128]).unwrap(); if let Ok(result) = ecrecover(sig, rec_id, msg) { - sdk.write(result.as_slice()); + Ok(result.into()) + } else { + Ok(Bytes::new()) } // TODO(dmitry123): Recover signature using ecdsa library once we have unconstrainted mode @@ -52,7 +54,7 @@ pub fn main_entry(mut sdk: SDK) { // sdk.write(&out); } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -62,16 +64,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/secp256r1/Cargo.toml b/contracts/eip7951/Cargo.toml similarity index 100% rename from contracts/secp256r1/Cargo.toml rename to contracts/eip7951/Cargo.toml diff --git a/contracts/secp256r1/README.md b/contracts/eip7951/README.md similarity index 100% rename from contracts/secp256r1/README.md rename to contracts/eip7951/README.md diff --git a/contracts/secp256r1/lib.rs b/contracts/eip7951/lib.rs similarity index 92% rename from contracts/secp256r1/lib.rs rename to contracts/eip7951/lib.rs index 8a32d3e59..5d60f85cd 100644 --- a/contracts/secp256r1/lib.rs +++ b/contracts/eip7951/lib.rs @@ -3,7 +3,7 @@ extern crate alloc; extern crate core; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, ExitCode, SharedAPI}; +use fluentbase_sdk::{system_entrypoint, Bytes, ExitCode, SharedAPI}; use revm_precompile::secp256r1::{p256_verify, P256VERIFY_BASE_GAS_FEE}; /// Main entry point for the secp256r1 wrapper contract. @@ -18,19 +18,14 @@ use revm_precompile::secp256r1::{p256_verify, P256VERIFY_BASE_GAS_FEE}; /// Output: /// - Returns a single byte with value 1 if the signature is valid /// - Returns an empty byte array if the signature is invalid -pub fn main_entry(mut sdk: SDK) { - let input_length = sdk.input_size(); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); - sdk.sync_evm_gas(P256VERIFY_BASE_GAS_FEE); - let result = match p256_verify(input, u64::MAX) { - Ok(result) => result, - Err(_) => sdk.native_exit(ExitCode::PrecompileError), - }; - sdk.write(&result.bytes); +pub fn main_entry(sdk: &mut SDK) -> Result { + let input = sdk.input(); + sdk.sync_evm_gas(P256VERIFY_BASE_GAS_FEE)?; + let result = p256_verify(input, u64::MAX).map_err(|_| ExitCode::PrecompileError)?; + Ok(result.bytes) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -44,16 +39,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/evm/Cargo.toml b/contracts/evm/Cargo.toml index b79a6a636..356a281bf 100644 --- a/contracts/evm/Cargo.toml +++ b/contracts/evm/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] fluentbase-sdk = { workspace = true, default-features = false } fluentbase-evm = { workspace = true, default-features = false } +spin = { version = "0.10.0", default-features = false, features = ["mutex"] } +#talc = { version = "4.4.3", default-features = false, features = ["lock_api"] } [dev-dependencies] fluentbase-testing = { workspace = true } diff --git a/contracts/evm/README.md b/contracts/evm/README.md index f369ea3c4..f3654015e 100644 --- a/contracts/evm/README.md +++ b/contracts/evm/README.md @@ -3,8 +3,8 @@ A minimal contract wrapper that embeds the fluentbase-evm interpreter into a smart-contract friendly entrypoint. It handles two flows: -- deploy_entry: runs EVM init code and commits the resulting runtime bytecode to metadata. -- main_entry: executes previously deployed bytecode with the provided call data. +- `deploy_entry`: runs EVM init code and commits the resulting runtime bytecode to metadata. +- `main_entry`: executes previously deployed bytecode with the provided call data. This crate does not implement EVM itself — it wires the host (SharedAPI) to the interpreter from crates/evm and applies basic network rules relevant to deployment. @@ -18,9 +18,11 @@ basic network rules relevant to deployment. ## Entrypoints -- deploy_entry: executes init bytecode, enforces EIP-3541 (no 0xEF prefix) and EIP-170 (code size), charges CODEDEPOSIT, +- `deploy_entry`: executes init bytecode, enforces EIP-3541 (no 0xEF prefix) and EIP-170 (code size), charges + CODEDEPOSIT, then stores code hash (offset 0) and raw bytecode (offset 32) in metadata. -- main_entry: loads analyzed bytecode from metadata, runs the interpreter with call data, settles fuel delta, and writes +- `main_entry`: loads analyzed bytecode from metadata, runs the interpreter with call data, settles fuel delta, and + writes return data. Relevant functions in lib.rs: diff --git a/contracts/evm/lib.rs b/contracts/evm/lib.rs index 3cc2d3927..f649461d6 100644 --- a/contracts/evm/lib.rs +++ b/contracts/evm/lib.rs @@ -3,37 +3,22 @@ extern crate alloc; extern crate core; -use fluentbase_evm::{bytecode::AnalyzedBytecode, gas, EthVM, EthereumMetadata, ExecutionResult}; +use alloc::vec::Vec; +use core::convert::AsRef; +use fluentbase_evm::{ + bytecode::AnalyzedBytecode, gas, gas::Gas, opcodes::interruptable_instruction_table, + types::InterruptionOutcome, EthVM, EthereumMetadata, ExecutionResult, InterpreterAction, +}; use fluentbase_sdk::{ - entrypoint, keccak256, Bytes, ContextReader, ExitCode, SharedAPI, B256, EVM_MAX_CODE_SIZE, + bincode, byteorder, byteorder::ByteOrder, crypto::crypto_keccak256, entrypoint, Bytes, + ContextReader, ExitCode, RuntimeInterruptionOutcomeV1, RuntimeNewFrameInputV1, SharedAPI, + SyscallInvocationParams, B256, EVM_MAX_CODE_SIZE, FUEL_DENOM_RATE, }; +use spin::MutexGuard; -/// Store EVM bytecode and its keccak256 hash in contract metadata. -/// Hash is written at offset 0, raw bytecode at offset 32. -pub(crate) fn commit_evm_bytecode(sdk: &mut SDK, evm_bytecode: Bytes) { - let contract_address = sdk.context().contract_address(); - let evm_code_hash = keccak256(evm_bytecode.as_ref()); - let analyzed_bytecode = AnalyzedBytecode::new(evm_bytecode, evm_code_hash); - let raw_metadata = EthereumMetadata::Analyzed(analyzed_bytecode).write_to_bytes(); - sdk.metadata_write(&contract_address, 0, raw_metadata) - .unwrap(); -} - -/// Load analyzed EVM bytecode from contract metadata. -/// Returns None if metadata is empty or code hash is zero/KECCAK_EMPTY. -pub(crate) fn load_evm_bytecode(sdk: &SDK) -> Option { - // We use bytecode address because contract can be called using DELEGATECALL - let bytecode_address = sdk.context().contract_bytecode_address(); - // Read metadata size, if it's zero, then an account is not assigned to the EVM runtime - let (metadata_size, is_account_ownable, _, _) = sdk.metadata_size(&bytecode_address).unwrap(); - if !is_account_ownable { - return None; - } - let metadata = sdk - .metadata_copy(&bytecode_address, 0, metadata_size) - .unwrap(); - // Get EVM bytecode from metadata - Some(match EthereumMetadata::read_from_bytes(&metadata)? { +/// Transforms metadata into analyzed EVM bytecode when possible. +pub(crate) fn evm_bytecode_from_metadata(metadata: &Bytes) -> Option { + Some(match EthereumMetadata::read_from_bytes(metadata)? { EthereumMetadata::Legacy(bytecode) => { AnalyzedBytecode::new(bytecode.bytecode, bytecode.hash) } @@ -41,66 +26,244 @@ pub(crate) fn load_evm_bytecode(sdk: &SDK) -> Option(mut sdk: SDK, result: ExecutionResult) { - let consumed_diff = result.chargeable_fuel(); - sdk.charge_fuel(consumed_diff); - sdk.write(result.output.as_ref()); - sdk.native_exit(if result.result.is_revert() { - ExitCode::Panic +static SAVED_EVM_CONTEXT: spin::Once>> = spin::Once::new(); + +fn lock_evm_context<'a>() -> MutexGuard<'a, Vec> { + let cached_state = SAVED_EVM_CONTEXT.call_once(|| spin::Mutex::new(Vec::new())); + debug_assert!( + !cached_state.is_locked(), + "evm: spin mutex is locked, looks like memory corruption" + ); + cached_state.lock() +} + +fn restore_evm_context_or_create<'a>( + cached_state: &'a mut MutexGuard>, + context: impl ContextReader, + input: Bytes, + return_data: Bytes, +) -> &'a mut EthVM { + // If return data is empty, then we create new EVM frame + if return_data.is_empty() { + // Decode new frame input + let (new_frame_input, _) = bincode::decode_from_slice::( + input.as_ref(), + bincode::config::legacy(), + ) + .unwrap(); + // If analyzed, bytecode is not presented then extract it from the input + // (contract deployment stage) + let (analyzed_bytecode, contract_input) = if !new_frame_input.metadata.is_empty() { + let Some(analyzed_bytecode) = evm_bytecode_from_metadata(&new_frame_input.metadata) + else { + unreachable!("evm: a valid metadata must be provided") + }; + (analyzed_bytecode, new_frame_input.input) + } else { + let analyzed_bytecode = + AnalyzedBytecode::new(new_frame_input.input.clone(), B256::ZERO); + (analyzed_bytecode, Bytes::new()) + }; + let eth_vm = EthVM::new(context, contract_input, analyzed_bytecode); + // Push new EthVM frame (new frame is created) + cached_state.push(eth_vm); + cached_state.last_mut().unwrap() } else { - ExitCode::Err - }); + drop(context); + let ( + RuntimeInterruptionOutcomeV1 { + halted_frame, + output, + fuel_consumed, + fuel_refunded, + exit_code, + }, + _, + ) = bincode::decode_from_slice::( + return_data.as_ref(), + bincode::config::legacy(), + ) + .unwrap(); + let Some(eth_vm) = cached_state.last_mut() else { + unreachable!("evm: missing cached evm state, can't resume execution") + }; + let mut gas = Gas::new_spent(fuel_consumed / FUEL_DENOM_RATE); + gas.record_refund(fuel_refunded / FUEL_DENOM_RATE as i64); + { + let dirty_gas = &mut eth_vm.interpreter.gas; + if !dirty_gas.record_cost(gas.spent()) { + unreachable!( + "evm: a fatal gas mis-sync between runtimes, this should never happen" + ); + } + eth_vm.interpreter.extend.committed_gas = *dirty_gas; + } + let exit_code = ExitCode::from(exit_code); + _ = eth_vm + .interpreter + .extend + .interruption_outcome + .insert(InterruptionOutcome { + output, + gas, + exit_code, + halted_frame, + }); + eth_vm + } } /// Deploy entry for EVM contracts. /// Runs init bytecode, enforces EIP-3541 and EIP-170, charges CODEDEPOSIT gas, /// then commits the resulting runtime bytecode to metadata. pub fn deploy_entry(mut sdk: SDK) { - let input: Bytes = sdk.input().into(); - let analyzed_bytecode = AnalyzedBytecode::new(input, B256::ZERO); - - let mut result = - EthVM::new(sdk.context(), Bytes::default(), analyzed_bytecode).run_the_loop(&mut sdk); - if !result.result.is_ok() { - return handle_not_ok_result(sdk, result); - } + let (output, exit_code) = deploy_inner(&mut sdk, lock_evm_context()); + let mut exit_code_le: [u8; 4] = [0u8; 4]; + byteorder::LE::write_i32(&mut exit_code_le, exit_code as i32); + let mut result = Vec::with_capacity(4 + output.len()); + result.extend_from_slice(&exit_code_le); + result.extend_from_slice(&output); + sdk.write(&result); +} - // EIP-3541 and EIP-170 checks - if result.output.first() == Some(&0xEF) { - sdk.native_exit(ExitCode::PrecompileError); - } else if result.output.len() > EVM_MAX_CODE_SIZE { - sdk.native_exit(ExitCode::PrecompileError); - } - let gas_for_code = result.output.len() as u64 * gas::CODEDEPOSIT; - if !result.gas.record_cost(gas_for_code) { - sdk.native_exit(ExitCode::OutOfFuel); +fn deploy_inner( + sdk: &mut SDK, + mut cached_state: MutexGuard>, +) -> (Bytes, ExitCode) { + let evm = restore_evm_context_or_create( + &mut cached_state, + sdk.context(), + sdk.bytes_input(), + sdk.return_data(), + ); + let instruction_table = interruptable_instruction_table::(); + match evm.run_step(&instruction_table, sdk) { + InterpreterAction::Return(result) => { + let committed_gas = evm.interpreter.extend.committed_gas; + _ = cached_state.pop(); + let mut result = ExecutionResult { + result: result.result, + output: result.output, + committed_gas, + gas: result.gas, + }; + if result.result.is_ok() { + // EIP-3541 and EIP-170 checks + if result.output.first() == Some(&0xEF) { + return (Bytes::new(), ExitCode::CreateContractStartingWithEF); + } else if result.output.len() > EVM_MAX_CODE_SIZE { + return (Bytes::new(), ExitCode::CreateContractSizeLimit); + } + let gas_for_code = result.output.len() as u64 * gas::CODEDEPOSIT; + if !result.gas.record_cost(gas_for_code) { + return (Bytes::new(), ExitCode::OutOfFuel); + } + let consumed_diff = result.chargeable_fuel(); + sdk.charge_fuel(consumed_diff); + // We intentionally don't charge gas for these opcodes + // to keep full compatibility with an EVM deployment process + let evm_code_hash = crypto_keccak256(result.output.as_ref()); + let analyzed_bytecode = AnalyzedBytecode::new(result.output, evm_code_hash); + let evm_bytecode = EthereumMetadata::Analyzed(analyzed_bytecode).write_to_bytes(); + (evm_bytecode, ExitCode::Ok) + } else { + let consumed_diff = result.chargeable_fuel(); + sdk.charge_fuel(consumed_diff); + let exit_code = if result.result.is_revert() { + ExitCode::Panic + } else { + ExitCode::Err + }; + (result.output, exit_code) + } + } + InterpreterAction::SystemInterruption { + code_hash, + input, + fuel_limit, + state, + } => { + let input_offset = input.as_ptr() as usize; + evm.sync_evm_gas(sdk); + let syscall_params = SyscallInvocationParams { + code_hash, + input: input_offset..(input_offset + input.len()), + fuel_limit: fuel_limit.unwrap_or(u64::MAX), + state, + fuel16_ptr: 0, + } + .encode(); + (syscall_params.into(), ExitCode::InterruptionCalled) + } + InterpreterAction::NewFrame(_) => unreachable!("frames can't be produced"), } - - let consumed_diff = result.chargeable_fuel(); - sdk.charge_fuel(consumed_diff); - - // We intentionally don't charge gas for these opcodes - // to keep full compatibility with an EVM deployment process - commit_evm_bytecode(&mut sdk, result.output); } /// Main entry for executing deployed EVM bytecode. /// Loads analyzed code from metadata, runs EthVM with call input, settles fuel, /// and writes the returned data. +#[inline(never)] pub fn main_entry(mut sdk: SDK) { - let Some(analyzed_bytecode) = load_evm_bytecode(&sdk) else { - return; - }; - let result = - EthVM::new(sdk.context(), sdk.bytes_input(), analyzed_bytecode).run_the_loop(&mut sdk); - if !result.result.is_ok() { - return handle_not_ok_result(sdk, result); + let (output, exit_code) = main_inner(&mut sdk, lock_evm_context()); + let mut exit_code_le: [u8; 4] = [0u8; 4]; + byteorder::LE::write_i32(&mut exit_code_le, exit_code as i32); + let mut result = Vec::with_capacity(4 + output.len()); + result.extend_from_slice(&exit_code_le); + result.extend_from_slice(&output); + sdk.write(&result); +} + +#[inline(never)] +fn main_inner( + sdk: &mut SDK, + mut cached_state: MutexGuard>, +) -> (Bytes, ExitCode) { + let evm = restore_evm_context_or_create( + &mut cached_state, + // Pass information about execution context (contract address, caller) into the EthVM, + // but it's used only if EthVM is not created (aka first call, not resume) + sdk.context(), + // Input of the smart contract + sdk.bytes_input(), + // Return data indicates the existence of interrupted state, + // if we have return data not empty, + // then we've executed this frame before and need to resume + sdk.return_data(), + ); + let instruction_table = interruptable_instruction_table::(); + match evm.run_step(&instruction_table, sdk) { + InterpreterAction::Return(result) => { + evm.sync_evm_gas(sdk); + _ = cached_state.pop(); + let exit_code = if result.result.is_ok() { + ExitCode::Ok + } else if result.result.is_revert() { + ExitCode::Panic + } else { + ExitCode::Err + }; + (result.output, exit_code) + } + InterpreterAction::SystemInterruption { + code_hash, + input, + fuel_limit, + state, + } => { + let input_offset = input.as_ptr() as usize; + evm.sync_evm_gas(sdk); + let syscall_params = SyscallInvocationParams { + code_hash, + input: input_offset..(input_offset + input.len()), + fuel_limit: fuel_limit.unwrap_or(u64::MAX), + state, + fuel16_ptr: 0, + } + .encode(); + (syscall_params.into(), ExitCode::InterruptionCalled) + } + InterpreterAction::NewFrame(_) => unreachable!("evm: frames can't be produced"), } - let consumed_diff = result.chargeable_fuel(); - sdk.charge_fuel(consumed_diff); - sdk.write(result.output.as_ref()); } entrypoint!(main_entry, deploy_entry); @@ -109,7 +272,7 @@ entrypoint!(main_entry, deploy_entry); mod tests { use crate::{deploy_entry, main_entry}; use core::str::from_utf8; - use fluentbase_sdk::{hex, Address, ContractContextV1, PRECOMPILE_EVM_RUNTIME, U256}; + use fluentbase_sdk::{hex, Address, ContractContextV1, ExitCode, PRECOMPILE_EVM_RUNTIME, U256}; use fluentbase_testing::HostTestingContext; #[ignore] @@ -139,8 +302,11 @@ mod tests { { let sdk = sdk.with_input(hex!("45773e4e")); main_entry(sdk.clone()); - let bytes = &sdk.take_output()[64..75]; - assert_eq!("Hello World", from_utf8(bytes.as_ref()).unwrap()); + let output = sdk.take_output(); + let (exit_code_le, output) = output.split_at(4); + assert_eq!(exit_code_le, &[0, 0, 0, 0]); + let bytes = &output[64..75]; + assert_eq!("Hello World", from_utf8(bytes).unwrap()); } } } diff --git a/contracts/identity/lib.rs b/contracts/identity/lib.rs index 72e2b6100..837809278 100644 --- a/contracts/identity/lib.rs +++ b/contracts/identity/lib.rs @@ -3,28 +3,26 @@ extern crate alloc; extern crate core; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, ContextReader, ExitCode, SharedAPI}; +use fluentbase_sdk::{system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; use revm_precompile::{ calc_linear_cost_u32, identity::{IDENTITY_BASE, IDENTITY_PER_WORD}, }; -pub fn main_entry(mut sdk: impl SharedAPI) { +pub fn main_entry(sdk: &mut impl SharedAPI) -> Result { let gas_limit = sdk.context().contract_gas_limit(); let input_length = sdk.input_size(); // fail fast if we don't have enough fuel for the call let gas_used = calc_linear_cost_u32(input_length as usize, IDENTITY_BASE, IDENTITY_PER_WORD); if gas_used > gas_limit { - sdk.native_exit(ExitCode::OutOfFuel); + return Err(ExitCode::OutOfFuel); } - sdk.sync_evm_gas(gas_used); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); + sdk.sync_evm_gas(gas_used)?; // write an identical output - sdk.write(input); + Ok(sdk.bytes_input()) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -34,16 +32,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/kzg/lib.rs b/contracts/kzg/lib.rs index 5b03f0d28..5867f854f 100644 --- a/contracts/kzg/lib.rs +++ b/contracts/kzg/lib.rs @@ -2,24 +2,21 @@ extern crate alloc; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; +use fluentbase_sdk::{system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; -pub fn main_entry(mut sdk: impl SharedAPI) { +pub fn main_entry(sdk: &mut impl SharedAPI) -> Result { // read full input data let gas_limit = sdk.context().contract_gas_limit(); - let input_length = sdk.input_size(); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); - let input = Bytes::copy_from_slice(input); + let input = sdk.bytes_input().clone(); // call blake2 function let result = revm_precompile::kzg_point_evaluation::run(&input, gas_limit) - .unwrap_or_else(|_| sdk.native_exit(ExitCode::PrecompileError)); - sdk.sync_evm_gas(result.gas_used); + .map_err(|_| ExitCode::PrecompileError)?; + sdk.sync_evm_gas(result.gas_used)?; // write output - sdk.write(result.bytes.as_ref()); + Ok(result.bytes) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -30,16 +27,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 10_000_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/modexp/lib.rs b/contracts/modexp/lib.rs index 311b3861b..da5213fd2 100644 --- a/contracts/modexp/lib.rs +++ b/contracts/modexp/lib.rs @@ -3,9 +3,9 @@ extern crate alloc; extern crate core; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; +use fluentbase_sdk::{alloc_slice, system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; -pub fn main_entry(mut sdk: impl SharedAPI) { +pub fn main_entry(sdk: &mut impl SharedAPI) -> Result { // read full input data let gas_limit = sdk.context().contract_gas_limit(); let input_length = sdk.input_size(); @@ -14,13 +14,13 @@ pub fn main_entry(mut sdk: impl SharedAPI) { let input = Bytes::copy_from_slice(input); // call identity function let result = revm_precompile::modexp::berlin_run(&input, gas_limit) - .unwrap_or_else(|_| sdk.native_exit(ExitCode::PrecompileError)); - sdk.sync_evm_gas(result.gas_used); + .map_err(|_| ExitCode::PrecompileError)?; + sdk.sync_evm_gas(result.gas_used)?; // write output - sdk.write(result.bytes.as_ref()); + Ok(result.bytes) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -30,16 +30,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(&output, expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/nitro/Cargo.toml b/contracts/nitro/Cargo.toml index f621e1bc0..ea759ae58 100644 --- a/contracts/nitro/Cargo.toml +++ b/contracts/nitro/Cargo.toml @@ -28,10 +28,7 @@ crate-type = ["cdylib"] path = "lib.rs" [features] -default = [ - "std", - # "fluentbase-sdk/debug-print" -] +default = ["std"] std = ["fluentbase-sdk/std"] fluent-testnet = [ "fluentbase-sdk/fluent-testnet", diff --git a/contracts/ripemd160/lib.rs b/contracts/ripemd160/lib.rs index 24a11911e..786ad5498 100644 --- a/contracts/ripemd160/lib.rs +++ b/contracts/ripemd160/lib.rs @@ -2,9 +2,9 @@ extern crate alloc; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; +use fluentbase_sdk::{alloc_slice, system_entrypoint, Bytes, ContextReader, ExitCode, SharedAPI}; -pub fn main_entry(mut sdk: impl SharedAPI) { +pub fn main_entry(sdk: &mut impl SharedAPI) -> Result { // read full input data let gas_limit = sdk.context().contract_gas_limit(); let input_length = sdk.input_size(); @@ -13,13 +13,13 @@ pub fn main_entry(mut sdk: impl SharedAPI) { let input = Bytes::copy_from_slice(input); // call ripemd160 function let result = revm_precompile::hash::ripemd160_run(&input, gas_limit) - .unwrap_or_else(|_| sdk.native_exit(ExitCode::PrecompileError)); - sdk.sync_evm_gas(result.gas_used); + .map_err(|_| ExitCode::PrecompileError)?; + sdk.sync_evm_gas(result.gas_used)?; // write output - sdk.write(result.bytes.as_ref()); + Ok(result.bytes) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -29,16 +29,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/sha256/lib.rs b/contracts/sha256/lib.rs index 8e138b5aa..9561a3064 100644 --- a/contracts/sha256/lib.rs +++ b/contracts/sha256/lib.rs @@ -2,7 +2,9 @@ extern crate alloc; extern crate fluentbase_sdk; -use fluentbase_sdk::{alloc_slice, crypto::crypto_sha256, entrypoint, SharedAPI}; +use fluentbase_sdk::{ + alloc_slice, crypto::crypto_sha256, system_entrypoint, Bytes, ExitCode, SharedAPI, +}; /// Main entry point for the sha256 wrapper contract. /// This contract wraps the sha256 precompile (EIP-210) which computes the SHA-256 hash of a given input. @@ -13,14 +15,13 @@ use fluentbase_sdk::{alloc_slice, crypto::crypto_sha256, entrypoint, SharedAPI}; /// Output: /// - A 32-byte array representing the SHA-256 hash of the input /// -pub fn main_entry(mut sdk: SDK) { +pub fn main_entry(sdk: &mut SDK) -> Result { let input_length = sdk.input_size(); - let mut input = alloc_slice(input_length as usize); - sdk.read(&mut input, 0); - let gas_used = estimate_gas(input.len()); - sdk.sync_evm_gas(gas_used); - let result = crypto_sha256(&input); - sdk.write(result.as_ref()); + let gas_used = estimate_gas(input_length as usize); + sdk.sync_evm_gas(gas_used)?; + let input = sdk.input(); + let result = crypto_sha256(input); + Ok(result.into()) } /// Gas estimation for SHA-256 (based on an EVM gas model) @@ -32,7 +33,7 @@ fn estimate_gas(input_len: usize) -> u64 { 60 + (words as u64 * 12) } -entrypoint!(main_entry); +system_entrypoint!(main_entry); #[cfg(test)] mod tests { @@ -42,16 +43,15 @@ mod tests { fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { let gas_limit = 100_000; - let sdk = HostTestingContext::default() + let mut sdk = HostTestingContext::default() .with_input(Bytes::copy_from_slice(inputs)) .with_contract_context(ContractContextV1 { gas_limit, ..Default::default() }) .with_gas_limit(gas_limit); - main_entry(sdk.clone()); - let output = sdk.take_output(); - assert_eq!(output, expected); + let output = main_entry(&mut sdk).unwrap(); + assert_eq!(output.as_ref(), expected); let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; assert_eq!(gas_limit - gas_remaining, expected_gas); } diff --git a/contracts/universal-token/lib.rs b/contracts/universal-token/lib.rs index 69eedb93a..a972e9220 100644 --- a/contracts/universal-token/lib.rs +++ b/contracts/universal-token/lib.rs @@ -3,23 +3,21 @@ extern crate alloc; extern crate core; use alloc::vec::Vec; -use fluentbase_sdk::{ - debug_log_ext, entrypoint, Address, ContextReader, SharedAPI, UNIVERSAL_TOKEN_MAGIC_BYTES, +use fluentbase_sdk::{entrypoint, Address, ContextReader, SharedAPI, UNIVERSAL_TOKEN_MAGIC_BYTES}; +use fluentbase_svm::{ + fluentbase::token2022::{token2022_process, token2022_process_raw}, + pubkey::{Pubkey, PUBKEY_BYTES}, + token_2022, + token_2022::{extension::ExtensionType, instruction::AuthorityType, processor::Processor}, }; -use fluentbase_svm::fluentbase::token2022::{token2022_process, token2022_process_raw}; -use fluentbase_svm::pubkey::{Pubkey, PUBKEY_BYTES}; -use fluentbase_svm::token_2022; -use fluentbase_svm::token_2022::extension::ExtensionType; -use fluentbase_svm::token_2022::instruction::AuthorityType; -use fluentbase_svm::token_2022::processor::Processor; -use fluentbase_svm_common::common::{ - lamports_to_bytes, pubkey_from_evm_address, pubkey_try_from_slice, -}; -use fluentbase_svm_common::universal_token::{ - AllowanceParams, ApproveCheckedParams, ApproveParams, BurnCheckedParams, BurnParams, - CloseAccountParams, FreezeAccountParams, GetAccountDataSizeParams, InitializeAccountParams, - InitializeMintParams, MintToParams, RevokeParams, SetAuthorityParams, ThawAccountParams, - TransferFromParams, TransferParams, +use fluentbase_svm_common::{ + common::{lamports_to_bytes, pubkey_from_evm_address, pubkey_try_from_slice}, + universal_token::{ + AllowanceParams, ApproveCheckedParams, ApproveParams, BurnCheckedParams, BurnParams, + CloseAccountParams, FreezeAccountParams, GetAccountDataSizeParams, InitializeAccountParams, + InitializeMintParams, MintToParams, RevokeParams, SetAuthorityParams, ThawAccountParams, + TransferFromParams, TransferParams, + }, }; use fluentbase_universal_token::{ common::bytes_to_sig, @@ -146,7 +144,6 @@ fn transfer_from(sdk: &mut SDK, input: &[u8]) { } fn initialize_mint(sdk: &mut SDK, input: &[u8]) { - debug_log_ext!("IS_DEPLOY={}", IS_DEPLOY); let Ok(p) = InitializeMintParams::try_parse(input) else { sdk.evm_exit(ERR_MALFORMED_INPUT); }; @@ -249,7 +246,6 @@ fn approve(sdk: &mut SDK, input: &[u8]) { fn approve_checked(sdk: &mut SDK, input: &[u8]) { let Ok(p) = ApproveCheckedParams::try_parse(input) else { - debug_log_ext!(); sdk.evm_exit(ERR_MALFORMED_INPUT); }; let instruction = token_2022::instruction::approve_checked( diff --git a/crates/contracts/build.rs b/crates/contracts/build.rs index 63a2e7051..13e856b75 100644 --- a/crates/contracts/build.rs +++ b/crates/contracts/build.rs @@ -39,12 +39,13 @@ fn main() { let is_debug_profile = env::var("PROFILE").unwrap() == "debug"; for contracts_manifest_path in packages_resolver.manifest_dirs { + let contracts_manifest_path = contracts_manifest_path.to_str().unwrap().to_string(); let mut args = vec![ "build".to_string(), "--target".to_string(), "wasm32-unknown-unknown".to_string(), "--manifest-path".to_string(), - contracts_manifest_path.to_str().unwrap().to_string(), + contracts_manifest_path.clone(), "--target-dir".to_string(), target2_dir.to_str().unwrap().to_string(), "--color=always".to_string(), @@ -59,17 +60,7 @@ fn main() { if !is_debug_profile { args.push("--release".to_string()); } - let flags = vec![ - "-C".to_string(), - format!("link-arg=-zstack-size={}", 128 * 1024), - "-C".to_string(), - "panic=abort".to_string(), - "-C".to_string(), - "target-feature=+bulk-memory".to_string(), - ]; - let encoded_flags = flags.join("\x1f"); let status = Command::new("cargo") - .env("CARGO_ENCODED_RUSTFLAGS", encoded_flags) .args(args) .status() .expect("WASM compilation failure: failed to run cargo build"); diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 0332dc59b..384d935bd 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -10,10 +10,12 @@ keywords.workspace = true categories.workspace = true [dependencies] +# fluentbase fluentbase-sdk = { workspace = true } +# misc bitvec = { workspace = true } bincode = { workspace = true } - +serde = { workspace = true } # revm revm-primitives = { workspace = true } revm-bytecode = { workspace = true } @@ -29,6 +31,10 @@ std = [ "revm-interpreter/std", "revm-context/std", ] +serde = [ + "revm-interpreter/serde", + "fluentbase-sdk/serde" +] fluent-testnet = [ "fluentbase-sdk/fluent-testnet" ] diff --git a/crates/evm/src/evm.rs b/crates/evm/src/evm.rs index 21de5b454..a695ca354 100644 --- a/crates/evm/src/evm.rs +++ b/crates/evm/src/evm.rs @@ -13,15 +13,19 @@ use fluentbase_sdk::{Bytes, ContextReader, ExitCode, SharedAPI, FUEL_DENOM_RATE} use revm_bytecode::{Bytecode, LegacyAnalyzedBytecode}; use revm_interpreter::{ interpreter::{ExtBytecode, RuntimeFlags}, - CallInput, Gas, InputsImpl, Interpreter, InterpreterAction, SharedMemory, Stack, + CallInput, Gas, InputsImpl, InstructionTable, Interpreter, InterpreterAction, SharedMemory, + Stack, }; use revm_primitives::hardfork::SpecId; /// EVM interpreter wrapper running with an interruption extension. pub struct EthVM { - interpreter: Interpreter, + pub interpreter: Interpreter, } +unsafe impl Sync for EthVM {} +unsafe impl Send for EthVM {} + impl EthVM { /// Create a new VM instance bound to the given context and input. /// The bytecode must be pre-analyzed (jump table + hash preserved). @@ -118,6 +122,7 @@ impl EthVM { output, gas, exit_code, + halted_frame: false, }); } InterpreterAction::NewFrame(_) => unreachable!("frames can't be produced"), @@ -125,14 +130,23 @@ impl EthVM { } } - pub fn run_step(mut self, sdk: &mut SDK) -> InterpreterAction { - let instruction_table = interruptable_instruction_table(); + /// Executes 1 step of the interpreter run. + /// Returns EVM result plus precise gas/fuel accounting. + #[inline] + pub fn run_step<'a, SDK>( + &mut self, + instruction_table: &InstructionTable>, + sdk: &'a mut SDK, + ) -> InterpreterAction + where + SDK: SharedAPI, + { let mut sdk = HostWrapperImpl::wrap(sdk); self.interpreter.run_plain(&instruction_table, &mut sdk) } /// Commit interpreter gas deltas to the host (fuel) and snapshot the state. - pub(crate) fn sync_evm_gas(&mut self, sdk: &mut SDK) { + pub fn sync_evm_gas(&mut self, sdk: &mut SDK) { let (gas, committed_gas) = ( &self.interpreter.gas, &mut self.interpreter.extend.committed_gas, diff --git a/crates/evm/src/host.rs b/crates/evm/src/host.rs index 417ea215d..10ca06c94 100644 --- a/crates/evm/src/host.rs +++ b/crates/evm/src/host.rs @@ -15,7 +15,7 @@ pub(crate) trait HostWrapper { /// Wrapper that implements revm::Host for our SDK, but actual effects /// are performed through the interruption protocol. -pub(crate) struct HostWrapperImpl<'a, SDK: SharedAPI> { +pub struct HostWrapperImpl<'a, SDK: SharedAPI> { sdk: &'a mut SDK, } diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 5f80c8aa6..0843007e9 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -7,14 +7,14 @@ extern crate core; pub mod bytecode; mod evm; -mod host; +pub mod host; mod metadata; -mod opcodes; -mod types; +pub mod opcodes; +pub mod types; mod utils; pub use bytecode::AnalyzedBytecode; pub use evm::EthVM; pub use metadata::EthereumMetadata; -pub use revm_interpreter::gas; -pub use types::ExecutionResult; +pub use revm_interpreter::{gas, InterpreterAction}; +pub use types::{ExecutionResult, InterruptingInterpreter}; diff --git a/crates/evm/src/opcodes.rs b/crates/evm/src/opcodes.rs index ae5b544d3..92f4c43e7 100644 --- a/crates/evm/src/opcodes.rs +++ b/crates/evm/src/opcodes.rs @@ -5,7 +5,6 @@ //! provides a result. use crate::{ host::{HostWrapper, HostWrapperImpl}, - opcodes, types::{InterruptingInterpreter, InterruptionExtension, InterruptionOutcome}, utils::{global_memory_from_shared_buffer, interrupt_into_action}, }; @@ -33,6 +32,14 @@ macro_rules! unpack_interruption { if let Some(interruption_outcome) = take(&mut $context.interpreter.extend.interruption_outcome) { + if interruption_outcome.halted_frame { + let result = interruption_outcome.into_interpreter_result(); + $context + .interpreter + .bytecode + .set_action(InterpreterAction::Return(result)); + return; + } Some(interruption_outcome) } else { None @@ -535,27 +542,27 @@ pub const fn interruptable_instruction_table<'a, SDK: SharedAPI>( ) -> [Instruction>; 256] { let mut table = instruction_table::>(); use revm_bytecode::opcode::*; - table[BALANCE as usize] = opcodes::balance; - table[EXTCODESIZE as usize] = opcodes::extcodesize; - table[EXTCODECOPY as usize] = opcodes::extcodecopy; - table[EXTCODEHASH as usize] = opcodes::extcodehash; - table[BLOCKHASH as usize] = opcodes::blockhash; - table[SELFBALANCE as usize] = opcodes::selfbalance; - table[SLOAD as usize] = opcodes::sload; - table[SSTORE as usize] = opcodes::sstore; - table[TLOAD as usize] = opcodes::tload; - table[TSTORE as usize] = opcodes::tstore; - table[LOG0 as usize] = opcodes::log::<0, _>; - table[LOG1 as usize] = opcodes::log::<1, _>; - table[LOG2 as usize] = opcodes::log::<2, _>; - table[LOG3 as usize] = opcodes::log::<3, _>; - table[LOG4 as usize] = opcodes::log::<4, _>; - table[CREATE as usize] = opcodes::create::<_, false, _>; - table[CALL as usize] = opcodes::call; - table[CALLCODE as usize] = opcodes::call_code; - table[DELEGATECALL as usize] = opcodes::delegate_call; - table[CREATE2 as usize] = opcodes::create::<_, true, _>; - table[STATICCALL as usize] = opcodes::static_call; - table[SELFDESTRUCT as usize] = opcodes::selfdestruct; + table[BALANCE as usize] = balance; + table[EXTCODESIZE as usize] = extcodesize; + table[EXTCODECOPY as usize] = extcodecopy; + table[EXTCODEHASH as usize] = extcodehash; + table[BLOCKHASH as usize] = blockhash; + table[SELFBALANCE as usize] = selfbalance; + table[SLOAD as usize] = sload; + table[SSTORE as usize] = sstore; + table[TLOAD as usize] = tload; + table[TSTORE as usize] = tstore; + table[LOG0 as usize] = log::<0, _>; + table[LOG1 as usize] = log::<1, _>; + table[LOG2 as usize] = log::<2, _>; + table[LOG3 as usize] = log::<3, _>; + table[LOG4 as usize] = log::<4, _>; + table[CREATE as usize] = create::<_, false, _>; + table[CALL as usize] = call; + table[CALLCODE as usize] = call_code; + table[DELEGATECALL as usize] = delegate_call; + table[CREATE2 as usize] = create::<_, true, _>; + table[STATICCALL as usize] = static_call; + table[SELFDESTRUCT as usize] = selfdestruct; table } diff --git a/crates/evm/src/types.rs b/crates/evm/src/types.rs index 9e14476e7..e15855cad 100644 --- a/crates/evm/src/types.rs +++ b/crates/evm/src/types.rs @@ -6,12 +6,14 @@ use fluentbase_sdk::{Bytes, ExitCode, B256, FUEL_DENOM_RATE, U256}; use revm_interpreter::{interpreter::EthInterpreter, Gas, InstructionResult, InterpreterResult}; -#[derive(Debug)] +#[derive(Default, Debug, Clone)] /// Result of a host interruption (output, gas delta, and exit code). +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct InterruptionOutcome { pub output: Bytes, pub gas: Gas, pub exit_code: ExitCode, + pub halted_frame: bool, } impl InterruptionOutcome { @@ -47,7 +49,8 @@ impl InterruptionOutcome { } /// Extra per-interpreter state used during interruptions. -#[derive(Default)] +#[derive(Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct InterruptionExtension { pub interruption_outcome: Option, pub committed_gas: Gas, diff --git a/crates/genesis/build.rs b/crates/genesis/build.rs index 11b446901..869be7b00 100644 --- a/crates/genesis/build.rs +++ b/crates/genesis/build.rs @@ -1,7 +1,7 @@ use alloy_genesis::{ChainConfig, Genesis, GenesisAccount}; use fluentbase_sdk::{ - address, compile_wasm_to_rwasm_with_config, default_compilation_config, hex, keccak256, - Address, Bytes, B256, DEVELOPER_PREVIEW_CHAIN_ID, U256, + address, compile_wasm_to_rwasm_with_config, default_compilation_config, keccak256, Address, + Bytes, B256, DEVELOPER_PREVIEW_CHAIN_ID, U256, }; use std::{ collections::{BTreeMap, HashMap}, @@ -94,9 +94,6 @@ fn compile_all_contracts() -> HashMap<&'static [u8], (B256, Bytes)> { continue; } println!("compiling {}", contract.name); - if contract.name == "fluentbase_contracts_bls12381" { - println!("{}", hex::encode(contract.wasm_bytecode)); - } let start = Instant::now(); let rwasm_bytecode = compile_wasm_to_rwasm_with_config(contract.wasm_bytecode, config.clone()) diff --git a/crates/revm/src/executor.rs b/crates/revm/src/executor.rs index 913a3ddf5..16add63d4 100644 --- a/crates/revm/src/executor.rs +++ b/crates/revm/src/executor.rs @@ -7,19 +7,21 @@ use crate::{ ExecutionResult, NextAction, }; use cfg_if::cfg_if; +use core::mem::take; use fluentbase_runtime::{ default_runtime_executor, syscall_handler::{syscall_exec_impl, syscall_resume_impl}, - RuntimeContext, + RuntimeContext, RuntimeExecutor, }; use fluentbase_sdk::{ - is_delegated_runtime_address, keccak256, rwasm_core::RwasmModule, BlockContextV1, - BytecodeOrHash, Bytes, BytesOrRef, ContractContextV1, ExitCode, SharedContextInput, + bincode, is_delegated_runtime_address, is_execute_using_system_runtime, keccak256, + rwasm_core::RwasmModule, BlockContextV1, BytecodeOrHash, Bytes, BytesOrRef, ContractContextV1, + ExitCode, RuntimeInterruptionOutcomeV1, RuntimeNewFrameInputV1, SharedContextInput, SharedContextInputV1, SyscallInvocationParams, TxContextV1, FUEL_DENOM_RATE, STATE_DEPLOY, STATE_MAIN, U256, }; use revm::{ - bytecode::{opcode, Bytecode}, + bytecode::{opcode, ownable_account::OwnableAccountBytecode, Bytecode}, context::{Block, Cfg, ContextError, ContextTr, JournalTr, Transaction}, handler::FrameData, interpreter::{ @@ -118,7 +120,6 @@ fn execute_rwasm_frame>( ) -> Result::Error>> { let interpreter = &mut frame.interpreter; let is_create: bool = matches!(frame.input, FrameInput::Create(..)); - let is_static: bool = interpreter.runtime_flag.is_static(); let bytecode_address = interpreter .input .bytecode_address() @@ -128,6 +129,8 @@ fn execute_rwasm_frame>( .input .account_owner .unwrap_or_else(|| bytecode_address); + let meta_account = ctx.journal_mut().load_account_code(bytecode_address)?; + let meta_bytecode = meta_account.info.code.clone().unwrap_or_default(); // encode input with all related context info let context_input = SharedContextInput::V1(SharedContextInputV1 { @@ -162,8 +165,20 @@ fn execute_rwasm_frame>( .encode() .expect("revm: unable to encode shared context input") .to_vec(); - let inputs_bytes = interpreter.input.input.bytes(ctx); - context_input.extend_from_slice(&inputs_bytes); + let input = interpreter.input.input.bytes(ctx); + + match meta_bytecode { + Bytecode::OwnableAccount(v) if is_execute_using_system_runtime(&v.owner_address) => { + let new_frame_input = RuntimeNewFrameInputV1 { + metadata: v.metadata, + input, + }; + let new_frame_input = + bincode::encode_to_vec(&new_frame_input, bincode::config::legacy()).unwrap(); + context_input.extend(new_frame_input); + } + _ => context_input.extend_from_slice(&input), + } let rwasm_bytecode = match &*interpreter.bytecode { Bytecode::Rwasm(bytecode) => bytecode.clone(), @@ -179,6 +194,7 @@ fn execute_rwasm_frame>( )); } }; + let bytecode_hash = BytecodeOrHash::Bytecode { address: effective_bytecode_address, bytecode: rwasm_bytecode.module, @@ -222,15 +238,7 @@ fn execute_rwasm_frame>( let return_data: Bytes; return_data = runtime_context.execution_result.return_data.into(); - process_exec_result( - frame, - ctx, - inspector, - exit_code, - return_data, - is_create, - is_static, - ) + process_exec_result(frame, ctx, inspector, exit_code, return_data) } #[tracing::instrument(level = "info", skip_all)] @@ -240,7 +248,12 @@ fn execute_rwasm_resume>( interruption_outcome: SystemInterruptionOutcome, inspector: Option<&mut INSP>, ) -> Result::Error>> { - let SystemInterruptionOutcome { inputs, result, .. } = interruption_outcome; + let SystemInterruptionOutcome { + inputs, + result, + halted_frame, + .. + } = interruption_outcome; let result = result.unwrap(); let call_id = inputs.call_id; @@ -275,11 +288,35 @@ fn execute_rwasm_resume>( _ => ExitCode::UnknownError, }; + let bytecode_address = frame + .interpreter + .input + .bytecode_address() + .cloned() + .unwrap_or_else(|| frame.interpreter.input.target_address()); + let meta_account = ctx.journal_mut().load_account_code(bytecode_address)?; + let meta_bytecode = meta_account.info.code.clone().unwrap_or_default(); + let outcome: Bytes = match meta_bytecode { + Bytecode::OwnableAccount(v) if is_execute_using_system_runtime(&v.owner_address) => { + let outcome = RuntimeInterruptionOutcomeV1 { + halted_frame, + output: result.output, + fuel_consumed, + fuel_refunded, + exit_code, + }; + bincode::encode_to_vec(&outcome, bincode::config::legacy()) + .unwrap() + .into() + } + _ => result.output, + }; + let mut runtime_context = RuntimeContext::default(); let (fuel_consumed, fuel_refunded, exit_code) = syscall_resume_impl( &mut runtime_context, inputs.call_id, - result.output.as_ref(), + outcome.as_ref(), exit_code.into_i32(), fuel_consumed, fuel_refunded, @@ -308,20 +345,11 @@ fn execute_rwasm_resume>( .gas .record_refund(fuel_refunded / FUEL_DENOM_RATE as i64); - let result = process_exec_result::( - frame, - ctx, - inspector, - exit_code, - return_data, - inputs.is_create, - inputs.is_static, - )?; + let result = process_exec_result::(frame, ctx, inspector, exit_code, return_data)?; // If interruption ends with return, // then we should forget saved runtime, because otherwise it can cause memory leak match &result { NextAction::Return(_) => { - use fluentbase_runtime::RuntimeExecutor; default_runtime_executor().forget_runtime(call_id); } _ => {} @@ -329,6 +357,58 @@ fn execute_rwasm_resume>( Ok(result) } +fn get_ownable_account_mut<'a, CTX: ContextTr + 'a, INSP: Inspector>( + frame: &'a mut RwasmFrame, + ctx: &'a mut CTX, +) -> Result, ContextError<::Error>> { + let bytecode_address = frame + .interpreter + .input + .bytecode_address() + .cloned() + .unwrap_or_else(|| frame.interpreter.input.target_address()); + let bytecode_account = ctx.journal_mut().load_account_code(bytecode_address)?.data; + let bytecode_account = bytecode_account.info.code.clone(); + Ok(bytecode_account.and_then(|bytecode| match bytecode { + Bytecode::OwnableAccount(account) + if is_execute_using_system_runtime(&account.owner_address) => + { + Some(account) + } + _ => None, + })) +} + +fn process_system_runtime_result>( + frame: &mut RwasmFrame, + ctx: &mut CTX, + inspector: Option<&mut INSP>, + mut ownable_account: OwnableAccountBytecode, + exit_code: i32, + mut return_data: Bytes, +) -> Result::Error>> { + let is_create: bool = matches!(frame.input, FrameInput::Create(..)); + match exit_code { + // If we return `Ok` in deployment mode, then we assume we store new metadata in the output, + // it's used to rewrite the existing metadata to store custom bytecode. + 0 if is_create => { + ownable_account.metadata = take(&mut return_data); + let bytecode = Bytecode::OwnableAccount(ownable_account); + ctx.journal_mut() + .set_code(frame.interpreter.input.target_address(), bytecode); + } + // Don't do anything, execution default case + _ => {} + } + Ok(process_halt( + frame, + ctx, + inspector, + ExitCode::from(exit_code), + return_data, + )) +} + #[tracing::instrument(level = "info", skip_all)] fn process_exec_result>( frame: &mut RwasmFrame, @@ -336,11 +416,22 @@ fn process_exec_result>( inspector: Option<&mut INSP>, exit_code: i32, return_data: Bytes, - is_create: bool, - is_static: bool, ) -> Result::Error>> { // if we have success or failed exit code if exit_code <= 0 { + // If the result is produced by system runtime (like EVM, SVM, etc.) then use custom handler + if let Some(ownable_account) = get_ownable_account_mut::(frame, ctx)? { + return process_system_runtime_result( + frame, + ctx, + inspector, + ownable_account, + exit_code, + return_data, + ); + } + // A fallback with an execution result + let exit_code = ExitCode::from(exit_code); return Ok(process_halt(frame, ctx, inspector, exit_code, return_data)); } @@ -349,18 +440,23 @@ fn process_exec_result>( // try to parse execution params, if it's not possible, then return an error let Some(syscall_params) = SyscallInvocationParams::decode(&return_data) else { - unreachable!("can't decode invocation params"); + unreachable!("revm: can't decode invocation params"); }; + let gas = frame.interpreter.gas; let inputs = SystemInterruptionInputs { call_id, - is_create, syscall_params, - gas: frame.interpreter.gas, - is_static, + gas, }; - execute_rwasm_interruption::(frame, inspector, ctx, inputs) + execute_rwasm_interruption::( + frame, + inspector, + ctx, + inputs, + crate::syscall::DefaultRuntimeExecutorMemoryReader {}, + ) } #[tracing::instrument(level = "info", skip_all)] @@ -368,10 +464,9 @@ fn process_halt>( frame: &mut RwasmFrame, ctx: &mut CTX, inspector: Option<&mut INSP>, - exit_code: i32, + exit_code: ExitCode, return_data: Bytes, ) -> NextAction { - let exit_code = ExitCode::from(exit_code); let result = instruction_result_from_exit_code(exit_code, return_data.is_empty()); if let Some(inspector) = inspector { let evm_opcode = match result { diff --git a/crates/revm/src/result.rs b/crates/revm/src/result.rs index 8e4907e3b..715494bc4 100644 --- a/crates/revm/src/result.rs +++ b/crates/revm/src/result.rs @@ -34,6 +34,7 @@ pub fn instruction_result_from_exit_code( } ExitCode::Panic => InstructionResult::Revert, ExitCode::Err => InstructionResult::UnknownError, + ExitCode::InterruptionCalled => InstructionResult::Stop, /* Fluentbase Runtime Error Codes */ ExitCode::RootCallOnly => InstructionResult::RootCallOnly, ExitCode::MalformedBuiltinParams => InstructionResult::MalformedBuiltinParams, @@ -46,6 +47,7 @@ pub fn instruction_result_from_exit_code( ExitCode::StateChangeDuringStaticCall => InstructionResult::StateChangeDuringStaticCall, ExitCode::CreateContractSizeLimit => InstructionResult::CreateContractSizeLimit, ExitCode::CreateContractCollision => InstructionResult::CreateCollision, + ExitCode::CreateContractStartingWithEF => InstructionResult::CreateContractStartingWithEF, /* Trap Error Codes */ ExitCode::UnreachableCodeReached => InstructionResult::UnreachableCodeReached, ExitCode::MemoryOutOfBounds => InstructionResult::MemoryOutOfBounds, diff --git a/crates/revm/src/syscall.rs b/crates/revm/src/syscall.rs index a7bca7f60..0d8a68245 100644 --- a/crates/revm/src/syscall.rs +++ b/crates/revm/src/syscall.rs @@ -6,11 +6,13 @@ use crate::{ }; use core::cmp::min; use fluentbase_evm::EthereumMetadata; +use fluentbase_runtime::{default_runtime_executor, RuntimeExecutor}; use fluentbase_sdk::{ byteorder::{ByteOrder, LittleEndian, ReadBytesExt}, bytes::Buf, - calc_create_metadata_address, is_system_precompile, Address, Bytes, ExitCode, Log, LogData, - B256, FUEL_DENOM_RATE, KECCAK_EMPTY, PRECOMPILE_EVM_RUNTIME, STATE_MAIN, U256, + calc_create_metadata_address, is_execute_using_system_runtime, is_system_precompile, Address, + Bytes, ExitCode, Log, LogData, B256, FUEL_DENOM_RATE, KECCAK_EMPTY, PRECOMPILE_EVM_RUNTIME, + STATE_MAIN, U256, }; use revm::{ bytecode::{opcode, ownable_account::OwnableAccountBytecode, Bytecode}, @@ -24,11 +26,36 @@ use revm::{ }, primitives::{ hardfork::{SpecId, BERLIN, ISTANBUL, TANGERINE}, - wasm::wasm_max_code_size, + wasm::{wasm_max_code_size, WASM_MAX_CODE_SIZE}, }, Database, Inspector, }; -use std::{boxed::Box, vec::Vec}; +use rwasm::TrapCode; +use std::{boxed::Box, vec, vec::Vec}; + +pub(crate) trait MemoryReaderTr { + fn memory_read(&self, call_id: u32, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode>; +} + +pub(crate) struct DefaultRuntimeExecutorMemoryReader; +#[cfg(test)] +pub(crate) struct ForwardInputMemoryReader(Bytes); + +impl MemoryReaderTr for DefaultRuntimeExecutorMemoryReader { + fn memory_read(&self, call_id: u32, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { + default_runtime_executor().memory_read(call_id, offset, buffer) + } +} +#[cfg(test)] +impl MemoryReaderTr for ForwardInputMemoryReader { + fn memory_read(&self, _call_id: u32, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { + self.0 + .get(offset..offset + buffer.len()) + .ok_or(TrapCode::MemoryOutOfBounds)? + .copy_to_slice(buffer); + Ok(()) + } +} #[tracing::instrument(level = "info", skip_all)] pub(crate) fn execute_rwasm_interruption>( @@ -36,12 +63,18 @@ pub(crate) fn execute_rwasm_interruption>( mut inspector: Option<&mut INSP>, ctx: &mut CTX, inputs: SystemInterruptionInputs, + mr: impl MemoryReaderTr, ) -> Result::Error>> { let spec_id: SpecId = ctx.cfg().spec().into(); let current_target_address = frame.interpreter.input.target_address(); let account_owner_address = frame.interpreter.input.account_owner_address(); + let is_static = frame.interpreter.runtime_flag.is_static; + let is_system_runtime = account_owner_address + .filter(is_execute_using_system_runtime) + .is_some(); + macro_rules! return_result { ($output:expr, $result:ident) => {{ let output: Bytes = $output.into(); @@ -51,9 +84,9 @@ pub(crate) fn execute_rwasm_interruption>( gas: Gas::new_spent(frame.interpreter.gas.spent() - inputs.gas.spent()), }; frame.insert_interrupted_outcome(SystemInterruptionOutcome { - inputs: Box::new(inputs), + inputs, result: Some(result), - is_frame: false, + halted_frame: false, }); return Ok(NextAction::InterruptionResult); }}; @@ -63,6 +96,21 @@ pub(crate) fn execute_rwasm_interruption>( } macro_rules! return_halt { ($result:ident) => {{ + // For system runtime contracts, we always forward execution result to synchronize + // frames, otherwise it can cause memory corruption + if is_system_runtime { + let result = ExecutionResult { + result: instruction_result_from_exit_code(ExitCode::$result, true), + output: Bytes::new(), + gas: Gas::new_spent(frame.interpreter.gas.spent() - inputs.gas.spent()), + }; + frame.insert_interrupted_outcome(SystemInterruptionOutcome { + inputs, + result: Some(result), + halted_frame: true, + }); + return Ok(NextAction::InterruptionResult); + } let result = ExecutionResult { result: instruction_result_from_exit_code(ExitCode::$result, true), output: Bytes::new(), @@ -74,9 +122,9 @@ pub(crate) fn execute_rwasm_interruption>( macro_rules! return_frame { ($action:expr) => {{ frame.insert_interrupted_outcome(SystemInterruptionOutcome { - inputs: Box::new(inputs), + inputs, result: None, - is_frame: true, + halted_frame: false, }); return Ok($action); }}; @@ -103,17 +151,61 @@ pub(crate) fn execute_rwasm_interruption>( }}; } - use fluentbase_sdk::syscall::*; - match inputs.syscall_params.code_hash { - SYSCALL_ID_STORAGE_READ => { + macro_rules! get_input_validated { + (== $length:expr) => {{ + assert_halt!( + inputs.syscall_params.input.len() == $length + && inputs.syscall_params.state == STATE_MAIN, + MalformedBuiltinParams + ); + let mut input = [0u8; $length]; + if mr + .memory_read( + inputs.call_id, + inputs.syscall_params.input.start, + &mut input, + ) + .is_err() + { + return_result!(MemoryOutOfBounds) + } + input + }}; + (>= $length:expr) => {{ assert_halt!( - inputs.syscall_params.input.len() == 32 + inputs.syscall_params.input.len() >= $length && inputs.syscall_params.state == STATE_MAIN, MalformedBuiltinParams ); + let mut input = vec![0u8; $length]; + if mr + .memory_read( + inputs.call_id, + inputs.syscall_params.input.start, + &mut input, + ) + .is_err() + { + return_result!(MemoryOutOfBounds) + } + let call_id = inputs.call_id; + let remaining_offset = inputs.syscall_params.input.start + $length; + let remaining_length = + inputs.syscall_params.input.end - inputs.syscall_params.input.start - $length; + let lazy_contract_input = move || -> Result, TrapCode> { + let mut variable_input = vec![0u8; remaining_length]; + mr.memory_read(call_id, remaining_offset, &mut variable_input)?; + Ok(variable_input) + }; + (input, lazy_contract_input) + }}; + } - let slot = U256::from_le_slice(&inputs.syscall_params.input[0..32]); - // execute sload + use fluentbase_sdk::syscall::*; + match inputs.syscall_params.code_hash { + SYSCALL_ID_STORAGE_READ => { + let input = get_input_validated!(== 32); + let slot = U256::from_le_slice(&input[0..32]); let value = ctx.journal_mut().sload(current_target_address, slot)?; charge_gas!(sload_cost(spec_id, value.is_cold)); inspect!(opcode::SLOAD, [slot], [value.data]); @@ -122,16 +214,10 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_STORAGE_WRITE => { - assert_halt!( - inputs.syscall_params.input.len() == 32 + 32 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - // don't allow for static context - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); - let slot = U256::from_le_slice(&inputs.syscall_params.input[0..32]); - let new_value = U256::from_le_slice(&inputs.syscall_params.input[32..64]); - // execute sstore + assert_halt!(!is_static, StateChangeDuringStaticCall); + let input = get_input_validated!(== 64); + let slot = U256::from_le_slice(&input[0..32]); + let new_value = U256::from_le_slice(&input[32..64]); let value = ctx .journal_mut() .sstore(current_target_address, slot, new_value)?; @@ -150,17 +236,12 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_CALL => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 + 32 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - let target_address = Address::from_slice(&inputs.syscall_params.input[0..20]); - let value = U256::from_le_slice(&inputs.syscall_params.input[20..52]); - let contract_input = inputs.syscall_params.input.slice(52..); + let (input, lazy_contract_input) = get_input_validated!(>= 20 + 32); + let target_address = Address::from_slice(&input[0..20]); + let value = U256::from_le_slice(&input[20..52]); // for static calls with value greater than 0 - revert let has_transfer = !value.is_zero(); - if inputs.is_static && has_transfer { + if is_static && has_transfer { return_halt!(StateChangeDuringStaticCall); } let mut account_load = ctx.journal_mut().load_account_delegated(target_address)?; @@ -204,29 +285,28 @@ pub(crate) fn execute_rwasm_interruption>( ], [] ); - // create call inputs + // Read contract inputs after all gas charging + let Ok(contract_input) = lazy_contract_input() else { + return_halt!(MemoryOutOfBounds); + }; + // Create call inputs let call_inputs = Box::new(CallInputs { - input: CallInput::Bytes(contract_input), + input: CallInput::Bytes(contract_input.into()), gas_limit, target_address, caller: current_target_address, bytecode_address: target_address, value: CallValue::Transfer(value), scheme: CallScheme::Call, - is_static: inputs.is_static, + is_static, return_memory_offset: Default::default(), }); return_frame!(NextAction::NewFrame(FrameInput::Call(call_inputs))); } SYSCALL_ID_STATIC_CALL => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - let target_address = Address::from_slice(&inputs.syscall_params.input[0..20]); - let contract_input = inputs.syscall_params.input.slice(20..); + let (input, lazy_contract_input) = get_input_validated!(>= 20); + let target_address = Address::from_slice(&input[0..20]); let mut account_load = ctx.journal_mut().load_account_delegated(target_address)?; // set is_empty to false as we are not creating this account. account_load.is_empty = false; @@ -253,9 +333,13 @@ pub(crate) fn execute_rwasm_interruption>( ], [] ); - // create call inputs + // Read contract inputs after all gas charging + let Ok(contract_input) = lazy_contract_input() else { + return_halt!(MemoryOutOfBounds); + }; + // Create call inputs let call_inputs = Box::new(CallInputs { - input: CallInput::Bytes(contract_input), + input: CallInput::Bytes(contract_input.into()), gas_limit, target_address, caller: current_target_address, @@ -269,14 +353,9 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_CALL_CODE => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 + 32 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - let target_address = Address::from_slice(&inputs.syscall_params.input[0..20]); - let value = U256::from_le_slice(&inputs.syscall_params.input[20..52]); - let contract_input = inputs.syscall_params.input.slice(52..); + let (input, lazy_contract_input) = get_input_validated!(>= 20 + 32); + let target_address = Address::from_slice(&input[0..20]); + let value = U256::from_le_slice(&input[20..52]); let mut account_load = ctx.journal_mut().load_account_delegated(target_address)?; // set is_empty to false as we are not creating this account account_load.is_empty = false; @@ -295,7 +374,6 @@ pub(crate) fn execute_rwasm_interruption>( if !value.is_zero() { gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); } - // create call inputs inspect!( opcode::CALLCODE, [ @@ -309,28 +387,28 @@ pub(crate) fn execute_rwasm_interruption>( ], [] ); + // Read contract inputs after all gas charging + let Ok(contract_input) = lazy_contract_input() else { + return_halt!(MemoryOutOfBounds); + }; + // Create call inputs let call_inputs = Box::new(CallInputs { - input: CallInput::Bytes(contract_input), + input: CallInput::Bytes(contract_input.into()), gas_limit, target_address: current_target_address, caller: current_target_address, bytecode_address: target_address, value: CallValue::Transfer(value), scheme: CallScheme::CallCode, - is_static: inputs.is_static, + is_static, return_memory_offset: Default::default(), }); return_frame!(NextAction::NewFrame(FrameInput::Call(call_inputs))); } SYSCALL_ID_DELEGATE_CALL => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - let target_address = Address::from_slice(&inputs.syscall_params.input[0..20]); - let contract_input = inputs.syscall_params.input.slice(20..); + let (input, lazy_contract_input) = get_input_validated!(>= 20); + let target_address = Address::from_slice(&input[0..20]); let mut account_load = ctx.journal_mut().load_account_delegated(target_address)?; // set is_empty to false as we are not creating this account. account_load.is_empty = false; @@ -357,70 +435,80 @@ pub(crate) fn execute_rwasm_interruption>( ], [] ); - // create call inputs + // Read contract inputs after all gas charging + let Ok(contract_input) = lazy_contract_input() else { + return_halt!(MemoryOutOfBounds); + }; + // Create call inputs let call_inputs = Box::new(CallInputs { - input: CallInput::Bytes(contract_input), + input: CallInput::Bytes(contract_input.into()), gas_limit, target_address: current_target_address, caller: frame.interpreter.input.caller_address(), bytecode_address: target_address, value: CallValue::Apparent(frame.interpreter.input.call_value()), scheme: CallScheme::DelegateCall, - is_static: inputs.is_static, + is_static, return_memory_offset: Default::default(), }); return_frame!(NextAction::NewFrame(FrameInput::Call(call_inputs))); } SYSCALL_ID_CREATE | SYSCALL_ID_CREATE2 => { + assert_halt!(!is_static, StateChangeDuringStaticCall); + + // Make sure input doesn't exceed hard cap at least + const HARD_CAP: usize = WASM_MAX_CODE_SIZE + U256::BYTES + U256::BYTES; assert_halt!( - inputs.syscall_params.state == STATE_MAIN, + inputs.syscall_params.input.len() < HARD_CAP, MalformedBuiltinParams ); - // not allowed for static calls - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); - // make sure we have enough bytes inside input params + + // We have different derivation scheme and gas calculation for CREATE2 let is_create2 = inputs.syscall_params.code_hash == SYSCALL_ID_CREATE2; - let (scheme, value, init_code) = if is_create2 { - assert_halt!( - inputs.syscall_params.input.len() >= 32 + 32, - MalformedBuiltinParams - ); - let value = U256::from_le_slice(&inputs.syscall_params.input[0..32]); - let salt = U256::from_le_slice(&inputs.syscall_params.input[32..64]); - let init_code = inputs.syscall_params.input.slice(64..); - (CreateScheme::Create2 { salt }, value, init_code) + + let (input, lazy_init_code) = get_input_validated!(>= if is_create2 { + U256::BYTES + U256::BYTES } else { - assert_halt!( - inputs.syscall_params.input.len() >= 32, - MalformedBuiltinParams - ); - let value = U256::from_le_slice(&inputs.syscall_params.input[0..32]); - let init_code = inputs.syscall_params.input.slice(32..); - (CreateScheme::Create, value, init_code) + U256::BYTES + }); + + // Make sure we have enough bytes inside input params + let (scheme, value) = if is_create2 { + let value = U256::from_le_slice(&input[0..32]); + let salt = U256::from_le_slice(&input[32..64]); + (CreateScheme::Create2 { salt }, value) + } else { + let value = U256::from_le_slice(&input[0..32]); + (CreateScheme::Create, value) + }; + + // Make sure we don't exceed max possible init code + let init_code_length = inputs.syscall_params.input.len() - input.len(); + if init_code_length > 0 { + charge_gas!(gas::initcode_cost(init_code_length)); + } + let Ok(init_code) = lazy_init_code() else { + return_halt!(MemoryOutOfBounds); }; - // make sure we don't exceed max possible init code - // TODO(khasan): take into consideration evm.ctx().cfg().max_init_code let max_initcode_size = wasm_max_code_size(&init_code).unwrap_or(MAX_INITCODE_SIZE); assert_halt!( - init_code.len() <= max_initcode_size, + init_code_length <= max_initcode_size, CreateContractSizeLimit ); - if !init_code.is_empty() { - charge_gas!(gas::initcode_cost(init_code.len())); - } if is_create2 { - let Some(gas) = gas::create2_cost(init_code.len().try_into().unwrap()) else { + let Some(gas) = gas::create2_cost(init_code_length) else { return_halt!(OutOfFuel); }; charge_gas!(gas); } else { charge_gas!(gas::CREATE); }; + let mut gas_limit = frame.interpreter.gas.remaining(); gas_limit -= gas_limit / 64; charge_gas!(gas_limit); - // create inputs + match scheme { CreateScheme::Create => { inspect!(opcode::CREATE, [value, U256::ZERO, U256::ZERO], []); @@ -430,47 +518,60 @@ pub(crate) fn execute_rwasm_interruption>( } CreateScheme::Custom { .. } => {} } + let create_inputs = Box::new(CreateInputs { caller: current_target_address, scheme, value, - init_code, + init_code: init_code.into(), gas_limit, }); return_frame!(NextAction::NewFrame(FrameInput::Create(create_inputs))); } SYSCALL_ID_EMIT_LOG => { + assert_halt!(!is_static, StateChangeDuringStaticCall); + // Read the number of topics from the input and make sure the total numbers of + // topics don't exceed 4 elements assert_halt!( inputs.syscall_params.input.len() >= 1 && inputs.syscall_params.state == STATE_MAIN, MalformedBuiltinParams ); - // not allowed for static calls - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); - // read topics from input - let topics_len = inputs.syscall_params.input[0] as usize; + let mut input = [0u8; 1]; + if mr + .memory_read( + inputs.call_id, + inputs.syscall_params.input.start, + &mut input, + ) + .is_err() + { + return_result!(MemoryOutOfBounds) + } + let topics_len = input[0] as usize; assert_halt!(topics_len <= 4, MalformedBuiltinParams); + // Read topics from the input w/o data to make sure gas is charged for data len + // before it's read from the memory (to avoid extra memory allocation) let mut topics = Vec::with_capacity(topics_len); - assert_halt!( - inputs.syscall_params.input.len() >= 1 + topics_len * B256::len_bytes(), - MalformedBuiltinParams - ); + let (input, lazy_data_input) = get_input_validated!(>= 1 + topics_len * U256::BYTES); for i in 0..topics_len { let offset = 1 + i * B256::len_bytes(); - let topic = - &inputs.syscall_params.input.as_ref()[offset..(offset + B256::len_bytes())]; + let topic = &input[offset..(offset + B256::len_bytes())]; topics.push(B256::from_slice(topic)); } - // all remaining bytes are data - let data = inputs - .syscall_params - .input - .slice((1 + topics_len * B256::len_bytes())..); - // make sure we have enough gas to cover this operation - let Some(gas_cost) = gas::log_cost(topics_len as u8, data.len() as u64) else { + // Charge the gas based on the number of topics and remaining data length, we subtract + // topics and 1 (for topics length) + let data_length = inputs.syscall_params.input.len() - 1 - topics_len * U256::BYTES; + // Make sure we have enough gas before reading data input, otherwise a ddos attack can + // be applied + let Some(gas_cost) = gas::log_cost(topics_len as u8, data_length as u64) else { return_halt!(OutOfFuel); }; charge_gas!(gas_cost); + // all remaining bytes are data + let Ok(data) = lazy_data_input() else { + return_halt!(MemoryOutOfBounds); + }; match topics_len { 0 => inspect!(opcode::LOG0, [U256::ZERO, U256::ZERO], []), 1 => inspect!(opcode::LOG1, [U256::ZERO, U256::ZERO, topics[0].into()], []), @@ -504,25 +605,20 @@ pub(crate) fn execute_rwasm_interruption>( ), _ => unreachable!(), } - // write new log into the journal ctx.journal_mut().log(Log { address: current_target_address, - // it's safe to go unchecked here because we do topic check upper - data: LogData::new_unchecked(topics, data), + // SAFETY: It's safe to go unchecked here because we do topic check upper + data: LogData::new_unchecked(topics, data.into()), }); return_result!(Ok); } SYSCALL_ID_DESTROY_ACCOUNT => { - assert_halt!( - inputs.syscall_params.input.len() == 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let input = get_input_validated!(== 20); // not allowed for static calls - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); + assert_halt!(!is_static, StateChangeDuringStaticCall); // destroy an account - let target = Address::from_slice(&inputs.syscall_params.input[0..20]); + let target = Address::from_slice(&input[0..20]); let mut result = ctx .journal_mut() .selfdestruct(current_target_address, target)?; @@ -537,12 +633,8 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_BALANCE => { - assert_halt!( - inputs.syscall_params.input.len() == 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - let address = Address::from_slice(&inputs.syscall_params.input[0..20]); + let input = get_input_validated!(== 20); + let address = Address::from_slice(&input[0..20]); let value = ctx .journal_mut() .load_account(address) @@ -563,10 +655,7 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_SELF_BALANCE => { - assert_halt!( - inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let _ = get_input_validated!(== 0); let value = ctx .journal_mut() .load_account(current_target_address) @@ -577,12 +666,8 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_CODE_SIZE => { - assert_halt!( - inputs.syscall_params.state == STATE_MAIN - && inputs.syscall_params.input.len() == 20, - MalformedBuiltinParams - ); - let address = Address::from_slice(&inputs.syscall_params.input[0..20]); + let input = get_input_validated!(== 20); + let address = Address::from_slice(&input[0..20]); // Load an account with the bytecode let account = ctx.journal_mut().load_account_code(address)?; @@ -616,12 +701,8 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_CODE_HASH => { - assert_halt!( - inputs.syscall_params.state == STATE_MAIN - && inputs.syscall_params.input.len() == 20, - MalformedBuiltinParams - ); - let address = Address::from_slice(&inputs.syscall_params.input[0..20]); + let input = get_input_validated!(== 20); + let address = Address::from_slice(&input[0..20]); // Load an account from database let account = ctx.journal_mut().load_account_code(address)?; @@ -659,13 +740,9 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_CODE_COPY => { - assert_halt!( - inputs.syscall_params.state == STATE_MAIN - && inputs.syscall_params.input.len() == 20 + 8 * 2, - MalformedBuiltinParams - ); - let address = Address::from_slice(&inputs.syscall_params.input[0..20]); - let mut reader = inputs.syscall_params.input[20..].reader(); + let input = get_input_validated!(== 20 + 8 * 2); + let address = Address::from_slice(&input[0..20]); + let mut reader = input[20..].reader(); let code_offset = reader.read_u64::().unwrap(); let code_length = reader.read_u64::().unwrap(); @@ -737,17 +814,12 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_METADATA_SIZE => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - // syscall is allowed only for accounts that are owned by somebody let Some(account_owner_address) = account_owner_address else { return_halt!(MalformedBuiltinParams); }; + let input = get_input_validated!(== 20); // read an account from its address - let address = Address::from_slice(&inputs.syscall_params.input[..20]); + let address = Address::from_slice(&input[..20]); let mut account = ctx.journal_mut().load_account_code(address)?; // to make sure this account is ownable and owner by the same runtime, that allows // a runtime to modify any account it owns @@ -776,10 +848,6 @@ pub(crate) fn execute_rwasm_interruption>( return_result!(output, Ok); }; // execute a syscall - assert_halt!( - inputs.syscall_params.input.len() == 20, - MalformedBuiltinParams - ); let mut output = [0u8; 4 + 3]; LittleEndian::write_u32(&mut output, ownable_account_bytecode.metadata.len() as u32); output[4] = 0x01u8; // the account belongs to the same runtime @@ -789,39 +857,29 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_METADATA_ACCOUNT_OWNER => { - assert_halt!( - inputs.syscall_params.input.len() == 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - // syscall is allowed only for accounts that are owned by somebody - let Some(_account_owner_address) = account_owner_address else { + let Some(account_owner_address) = account_owner_address else { return_halt!(MalformedBuiltinParams); }; - let address = Address::from_slice(&inputs.syscall_params.input[..Address::len_bytes()]); + let input = get_input_validated!(== Address::len_bytes()); + let address = Address::from_slice(&input[..Address::len_bytes()]); + if address == current_target_address { + return_result!(account_owner_address.0, Ok); + } let account = ctx.journal_mut().load_account_code(address)?; match account.info.code.as_ref() { Some(Bytecode::OwnableAccount(ownable_account_bytecode)) => { return_result!(ownable_account_bytecode.owner_address.0, Ok) } - _ => {} + _ => return_result!(Address::ZERO.0, Ok), }; - return_result!(Address::ZERO.0, Ok) } + SYSCALL_ID_METADATA_CREATE => { - assert_halt!( - inputs.syscall_params.input.len() >= 32 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - // syscall is allowed only for accounts that are owned by somebody let Some(account_owner_address) = account_owner_address else { return_halt!(MalformedBuiltinParams); }; - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); - // read an account from its address - let salt = U256::from_be_slice(&inputs.syscall_params.input[..32]); - let metadata = inputs.syscall_params.input.slice(32..); + let (input, lazy_metadata_input) = get_input_validated!(>= 32); + let salt = U256::from_be_slice(&input); let derived_metadata_address = calc_create_metadata_address(&account_owner_address, &salt); let account = ctx @@ -829,34 +887,33 @@ pub(crate) fn execute_rwasm_interruption>( .load_account_code(derived_metadata_address)?; // Verify no deployment collision exists at derived address. // Check only code_hash and nonce - intentionally ignore balance to prevent - // frontrunning DoS where attacker funds address before legitimate creation. + // front-running DoS where attacker funds address before legitimate creation. // This matches Ethereum CREATE2 behavior: accounts can be pre-funded. if account.info.code_hash != KECCAK_EMPTY || account.info.nonce != 0 { return_result!(CreateContractCollision); } // create a new derived ownable account + let Ok(metadata_input) = lazy_metadata_input() else { + return_halt!(MemoryOutOfBounds); + }; ctx.journal_mut().set_code( derived_metadata_address, Bytecode::OwnableAccount(OwnableAccountBytecode::new( account_owner_address, - metadata.clone(), + metadata_input.into(), )), ); return_result!(Bytes::new(), Ok) } - SYSCALL_ID_METADATA_WRITE | SYSCALL_ID_METADATA_COPY => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - // syscall is allowed only for accounts that are owned by somebody + SYSCALL_ID_METADATA_WRITE => { let Some(account_owner_address) = account_owner_address else { return_halt!(MalformedBuiltinParams); }; + let (input, lazy_metadata_input) = get_input_validated!(>= 20 + 4); // read an account from its address - let address = Address::from_slice(&inputs.syscall_params.input[..20]); + let address = Address::from_slice(&input[..20]); + let _offset = LittleEndian::read_u32(&input[20..24]) as usize; let mut account = ctx.journal_mut().load_account_code(address)?; // to make sure this account is ownable and owner by the same runtime, that allows // a runtime to modify any account it owns @@ -870,67 +927,55 @@ pub(crate) fn execute_rwasm_interruption>( return_halt!(MalformedBuiltinParams) } }; - // execute a syscall - match inputs.syscall_params.code_hash { - // Full metadata replacement (offset parameter ignored for safety) - SYSCALL_ID_METADATA_WRITE => { - assert_halt!( - inputs.syscall_params.input.len() >= 20 + 4, - MalformedBuiltinParams - ); - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); - // Input format: address(20) + offset(4) + metadata(N) - // Offset is kept for backward compatibility but always skipped - let new_metadata = inputs.syscall_params.input.slice(24..); - let offset = - LittleEndian::read_u32(&inputs.syscall_params.input[20..24]) as usize; - let length = inputs.syscall_params.input[24..].len(); - // TODO(dmitry123): "figure out a way how to optimize it" - let mut metadata = ownable_account_bytecode.metadata.to_vec(); - metadata.resize(offset + length, 0); - metadata[offset..(offset + length)] - .copy_from_slice(&inputs.syscall_params.input[24..]); - // code might change, rewrite it with a new hash - let new_bytecode = Bytecode::OwnableAccount(OwnableAccountBytecode::new( - ownable_account_bytecode.owner_address, - new_metadata, - )); - ctx.journal_mut().set_code(address, new_bytecode); - return_result!(Bytes::new(), Ok) + let Ok(new_metadata) = lazy_metadata_input() else { + return_halt!(MemoryOutOfBounds); + }; + // code might change, rewrite it with a new hash + let new_bytecode = Bytecode::OwnableAccount(OwnableAccountBytecode::new( + ownable_account_bytecode.owner_address, + new_metadata.into(), + )); + ctx.journal_mut().set_code(address, new_bytecode); + return_result!(Bytes::new(), Ok) + } + + SYSCALL_ID_METADATA_COPY => { + let Some(account_owner_address) = account_owner_address else { + return_halt!(MalformedBuiltinParams); + }; + let input = get_input_validated!(== 28); + // read an account from its address + let address = Address::from_slice(&input[..20]); + let mut account = ctx.journal_mut().load_account_code(address)?; + // to make sure this account is ownable and owner by the same runtime, that allows + // a runtime to modify any account it owns + let ownable_account_bytecode = match account.info.code.as_mut() { + Some(Bytecode::OwnableAccount(ownable_account_bytecode)) + if ownable_account_bytecode.owner_address == account_owner_address => + { + ownable_account_bytecode } - SYSCALL_ID_METADATA_COPY => { - assert_halt!( - inputs.syscall_params.input.len() == 28, - MalformedBuiltinParams - ); - let offset = LittleEndian::read_u32(&inputs.syscall_params.input[20..24]); - let length = LittleEndian::read_u32(&inputs.syscall_params.input[24..28]); - // take min - let length = length.min(ownable_account_bytecode.metadata.len() as u32); - let metadata = ownable_account_bytecode - .metadata - .slice(offset as usize..(offset + length) as usize); - return_result!(metadata, Ok) + _ => { + return_halt!(MalformedBuiltinParams) } - _ => unreachable!(), - } + }; + let offset = LittleEndian::read_u32(&input[20..24]); + let length = LittleEndian::read_u32(&input[24..28]); + // take min + let length = length.min(ownable_account_bytecode.metadata.len() as u32); + let metadata = ownable_account_bytecode + .metadata + .slice(offset as usize..(offset + length) as usize); + return_result!(metadata, Ok) } SYSCALL_ID_METADATA_STORAGE_READ => { - // input: slot let Some(account_owner_address) = account_owner_address else { return_halt!(MalformedBuiltinParams); }; - const INPUT_LEN: usize = U256::BYTES; - let syscall_params = &inputs.syscall_params; - assert_halt!( - syscall_params.input.len() == INPUT_LEN && syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let input = get_input_validated!(== U256::BYTES); - let Ok(slot): Result<[u8; U256::BYTES], _> = - syscall_params.input.as_ref()[..U256::BYTES].try_into() - else { + let Ok(slot): Result<[u8; U256::BYTES], _> = input[..U256::BYTES].try_into() else { return_halt!(MalformedBuiltinParams) }; let slot_u256 = U256::from_le_bytes(slot); @@ -944,25 +989,16 @@ pub(crate) fn execute_rwasm_interruption>( return_halt!(MalformedBuiltinParams); }; // input: slot + value - const INPUT_LEN: usize = U256::BYTES + U256::BYTES; - let syscall_params = &inputs.syscall_params; - assert_halt!( - syscall_params.input.len() == INPUT_LEN && syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let input = get_input_validated!(== U256::BYTES + U256::BYTES); - let Ok(slot): Result<[u8; U256::BYTES], _> = - syscall_params.input.as_ref()[..U256::BYTES].try_into() - else { + let Ok(slot): Result<[u8; U256::BYTES], _> = input[..U256::BYTES].try_into() else { return_halt!(MalformedBuiltinParams) }; - let Ok(value): Result<[u8; U256::BYTES], _> = - syscall_params.input.as_ref()[U256::BYTES..].try_into() - else { + let Ok(value): Result<[u8; U256::BYTES], _> = input[U256::BYTES..].try_into() else { return_halt!(MalformedBuiltinParams) }; - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); + assert_halt!(!is_static, StateChangeDuringStaticCall); let slot_u256 = U256::from_le_bytes(slot); let value_u256 = U256::from_le_bytes(value); @@ -974,13 +1010,9 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_TRANSIENT_READ => { - assert_halt!( - inputs.syscall_params.input.len() == 32 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let input = get_input_validated!(== 32); // read value from storage - let slot = U256::from_le_slice(&inputs.syscall_params.input[0..32].as_ref()); + let slot = U256::from_le_slice(&input[0..32].as_ref()); let value = ctx.journal_mut().tload(current_target_address, slot); // charge gas charge_gas!(gas::WARM_STORAGE_READ_COST); @@ -990,15 +1022,11 @@ pub(crate) fn execute_rwasm_interruption>( } SYSCALL_ID_TRANSIENT_WRITE => { - assert_halt!( - inputs.syscall_params.input.len() == 64 - && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); - assert_halt!(!inputs.is_static, StateChangeDuringStaticCall); + let input = get_input_validated!(== 64); + assert_halt!(!is_static, StateChangeDuringStaticCall); // read input - let slot = U256::from_le_slice(&inputs.syscall_params.input[0..32]); - let value = U256::from_le_slice(&inputs.syscall_params.input[32..64]); + let slot = U256::from_le_slice(&input[0..32]); + let value = U256::from_le_slice(&input[32..64]); // charge gas charge_gas!(gas::WARM_STORAGE_READ_COST); ctx.journal_mut() @@ -1008,12 +1036,9 @@ pub(crate) fn execute_rwasm_interruption>( } // SYSCALL_ID_BLOCK_HASH => { - assert_halt!( - inputs.syscall_params.input.len() == 8 && inputs.syscall_params.state == STATE_MAIN, - MalformedBuiltinParams - ); + let input = get_input_validated!(== 8); charge_gas!(gas::BLOCKHASH); - let requested_block = LittleEndian::read_u64(&inputs.syscall_params.input[0..8]); + let requested_block = LittleEndian::read_u64(&input[0..8]); let current_block = ctx.block_number().as_limbs()[0]; // Why do we return in big-endian here? :facepalm: let hash = match current_block.checked_sub(requested_block) { @@ -1028,6 +1053,7 @@ pub(crate) fn execute_rwasm_interruption>( _ => return_halt!(MalformedBuiltinParams), } } + #[cfg(test)] mod code_copy_tests { use super::*; @@ -1071,19 +1097,18 @@ mod code_copy_tests { syscall_input[0..20].copy_from_slice(target_address.as_slice()); syscall_input[20..28].copy_from_slice(&code_offset.to_le_bytes()); syscall_input[28..36].copy_from_slice(&code_length.to_le_bytes()); + let mr = ForwardInputMemoryReader(syscall_input.into()); let syscall_params = SyscallInvocationParams { code_hash: SYSCALL_ID_CODE_COPY, - input: Bytes::from(syscall_input), + input: 0..mr.0.len(), state: STATE_MAIN, ..Default::default() }; let interruption_inputs = SystemInterruptionInputs { call_id: 0, - is_create: false, syscall_params, - is_static: false, gas: Gas::new(initial_gas), }; @@ -1093,6 +1118,7 @@ mod code_copy_tests { None, &mut ctx, interruption_inputs, + mr, ); assert!( @@ -1263,10 +1289,11 @@ mod metadata_write_tests { syscall_input.extend_from_slice(&test_address.0[..]); syscall_input.extend_from_slice(&offset.to_le_bytes()); syscall_input.extend_from_slice(&new_data); + let mr = ForwardInputMemoryReader(syscall_input.into()); let syscall_params = SyscallInvocationParams { code_hash: SYSCALL_ID_METADATA_WRITE, - input: Bytes::from(syscall_input), + input: 0..mr.0.len(), state: STATE_MAIN, fuel_limit: 1_000_000, ..Default::default() @@ -1274,9 +1301,7 @@ mod metadata_write_tests { let interruption_inputs = SystemInterruptionInputs { call_id: 0, - is_create: false, syscall_params, - is_static: false, gas: Gas::new(1_000_000), }; @@ -1285,6 +1310,7 @@ mod metadata_write_tests { None, &mut ctx, interruption_inputs, + mr, ); assert!( @@ -1296,7 +1322,6 @@ mod metadata_write_tests { let acc = ctx.journal_mut().load_account_code(test_address).unwrap(); match &acc.info.code { Some(Bytecode::OwnableAccount(ownable)) => { - assert_eq!(ownable.metadata.len(), 4); assert_eq!(ownable.metadata[..], new_data); } _ => panic!("Expected OwnableAccount bytecode"), @@ -1337,19 +1362,18 @@ mod metadata_write_tests { let mut syscall_input = Vec::with_capacity(32 + metadata.len()); syscall_input.extend_from_slice(&salt.to_be_bytes::<32>()); syscall_input.extend_from_slice(&metadata); + let mr = ForwardInputMemoryReader(syscall_input.into()); let syscall_params = SyscallInvocationParams { code_hash: SYSCALL_ID_METADATA_CREATE, - input: Bytes::from(syscall_input), + input: 0..mr.0.len(), state: STATE_MAIN, ..Default::default() }; let interruption_inputs = SystemInterruptionInputs { call_id: 0, - is_create: false, syscall_params, - is_static: false, gas: Gas::new(1_000_000), // Sufficient gas for the operation }; @@ -1359,6 +1383,7 @@ mod metadata_write_tests { None, &mut ctx, interruption_inputs, + mr, ); assert!( @@ -1411,7 +1436,7 @@ mod block_hash_tests { use std::fmt; #[derive(Debug, Clone)] - pub struct MockDbError(pub String); + pub(super) struct MockDbError(pub String); impl fmt::Display for MockDbError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1422,7 +1447,7 @@ mod block_hash_tests { impl Error for MockDbError {} impl DBErrorMarker for MockDbError {} - pub struct FailingMockDatabase; + struct FailingMockDatabase; impl Database for FailingMockDatabase { type Error = MockDbError; @@ -1464,10 +1489,11 @@ mod block_hash_tests { let mut syscall_input = vec![0u8; 8]; syscall_input[0..8].copy_from_slice(&requested_block.to_le_bytes()); + let mr = ForwardInputMemoryReader(syscall_input.into()); let syscall_params = SyscallInvocationParams { code_hash: SYSCALL_ID_BLOCK_HASH, - input: Bytes::from(syscall_input), + input: 0..mr.0.len(), state: STATE_MAIN, ..Default::default() }; @@ -1475,9 +1501,7 @@ mod block_hash_tests { let interruption_inputs = SystemInterruptionInputs { call_id: 0, syscall_params, - is_static: false, gas: Gas::new(10_000_000), - is_create: false, }; execute_rwasm_interruption::<_, NoOpInspector>( @@ -1485,6 +1509,7 @@ mod block_hash_tests { None, &mut ctx, interruption_inputs, + mr, )?; Ok(frame @@ -1516,18 +1541,17 @@ mod block_hash_tests { let requested_block: u64 = 900; let mut syscall_input = vec![0u8; 8]; syscall_input[0..8].copy_from_slice(&requested_block.to_le_bytes()); + let mr = ForwardInputMemoryReader(syscall_input.into()); let interruption_inputs = SystemInterruptionInputs { call_id: 0, syscall_params: SyscallInvocationParams { code_hash: SYSCALL_ID_BLOCK_HASH, - input: Bytes::from(syscall_input), + input: 0..mr.0.len(), state: STATE_MAIN, ..Default::default() }, - is_static: false, gas: Gas::new(10_000_000), - is_create: false, }; // Execute the syscall - should return Err, not Ok @@ -1536,6 +1560,7 @@ mod block_hash_tests { None, &mut ctx, interruption_inputs, + mr, ); // Assert that database error was propagated diff --git a/crates/revm/src/types.rs b/crates/revm/src/types.rs index a85c82c0c..df097a8a5 100644 --- a/crates/revm/src/types.rs +++ b/crates/revm/src/types.rs @@ -1,7 +1,6 @@ use crate::ExecutionResult; use fluentbase_sdk::SyscallInvocationParams; use revm::interpreter::Gas; -use std::boxed::Box; /// A system interruption input params #[derive(Clone, Debug, PartialEq, Eq)] @@ -13,21 +12,20 @@ pub struct SystemInterruptionInputs { /// A gas snapshot assigned before the interruption. /// We need this to calculate the final amount of gas charged for the entire interruption. pub gas: Gas, - /// Indicates is interruption happen inside contact deployment. - pub is_create: bool, - /// Indicates is interruption happen inside static call. - pub is_static: bool, } /// An interruption outcome. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SystemInterruptionOutcome { /// Original inputs. - pub inputs: Box, + pub inputs: SystemInterruptionInputs, /// An interruption execution result. /// It can be empty for frame creation, /// where we don't know the result until the frame is executed. pub result: Option, - /// Indicated is it a nested frame call or not. - pub is_frame: bool, + /// Indicates was the frame halted before execution. + /// When we do CALL-like op we can halt execution during the frame creation, we + /// should handle this to forward inside the system runtime to make sure all frames + /// are terminated gracefully. + pub halted_frame: bool, } diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index cd72007b1..202030e68 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -15,9 +15,11 @@ fluentbase-types = { workspace = true } rwasm = { workspace = true } # wasmtime -wasmtime = { version = "34.0.1", package = "wasmtime-rwasm", optional = true, features = ["disable-fpu", "cache"] } -anyhow = { version = "1.0.98", default-features = false, optional = true } -smallvec = { version = "1.15.1", optional = true } +#wasmtime = { version = "34.0.1", package = "wasmtime-rwasm", features = ["disable-fpu", "cache"] } +wasmtime = { version = "34.0.1", package = "wasmtime-rwasm", features = ["disable-fpu", "cache"] } +#wasmtime = { path = "../../../wasmtime/crates/wasmtime", package = "wasmtime-rwasm", features = ["disable-fpu", "cache"] } +anyhow = { version = "1.0.98", default-features = false } +smallvec = { version = "1.15.1" } # misc k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } @@ -54,9 +56,6 @@ debug-print = [ # "rwasm/debug-print", ] wasmtime = [ - "dep:wasmtime", - "dep:anyhow", - "dep:smallvec", "rwasm/wasmtime", "rwasm/cache-compiled-artifacts", ] diff --git a/crates/runtime/src/context.rs b/crates/runtime/src/context.rs index 2b0109158..071ecad6b 100644 --- a/crates/runtime/src/context.rs +++ b/crates/runtime/src/context.rs @@ -56,6 +56,21 @@ impl RuntimeContext { self } + /// Extract serialized resumable context + pub fn take_resumable_context_serialized(&mut self) -> Option> { + // Take resumable context from execution context + let resumable_context = self.resumable_context.take()?; + if resumable_context.is_root { + unimplemented!("validate this logic, might not be ok in STF mode"); + } + // serialize the delegated execution state, + // but we don't serialize registers and stack state, + // instead we remember it inside the internal structure + // and assign a special identifier for recovery + let result = resumable_context.params.encode(); + Some(result) + } + /// Clears the accumulated output buffer. pub fn clear_output(&mut self) { self.execution_result.output.clear(); diff --git a/crates/runtime/src/executor.rs b/crates/runtime/src/executor.rs index 874fd33c5..258261c5a 100644 --- a/crates/runtime/src/executor.rs +++ b/crates/runtime/src/executor.rs @@ -4,7 +4,7 @@ mod local_executor; use crate::{ module_factory::ModuleFactory, - runtime::{ExecutionMode, StrategyRuntime}, + runtime::{ExecutionMode, RwasmRuntime, SystemRuntime}, RuntimeContext, }; use fluentbase_types::{ @@ -13,10 +13,7 @@ use fluentbase_types::{ }; use local_executor::LocalExecutor; use rwasm::{ExecutionEngine, FuelConfig, ImportLinker, RwasmModule, Strategy, TrapCode}; -use std::{ - mem::take, - sync::Arc, -}; +use std::{mem::take, sync::Arc}; /// Finalized outcome of a single runtime invocation. /// @@ -55,7 +52,7 @@ pub struct ExecutionInterruption { /// Fuel to refund to the caller at the interruption point. pub fuel_refunded: i64, /// Encoded interruption payload (e.g., delegated call parameters). - pub output: Vec, + pub return_data: Vec, } /// Result of running or resuming a runtime. @@ -115,6 +112,13 @@ pub trait RuntimeExecutor { /// /// Intended to be invoked at the beginning of a new transaction. fn reset_call_id_counter(&mut self); + + fn memory_read( + &mut self, + call_id: u32, + offset: usize, + buffer: &mut [u8], + ) -> Result<(), TrapCode>; } /// Returns a default runtime executor. @@ -183,7 +187,7 @@ impl RuntimeFactoryExecutor { fuel_consumed: interruption.fuel_consumed, fuel_refunded: interruption.fuel_refunded, // The output we map into return data - output: interruption.output, + output: interruption.return_data, return_data: vec![], } } @@ -208,47 +212,48 @@ impl RuntimeFactoryExecutor { if let Some(store_fuel_consumed) = fuel_consumed { execution_result.fuel_consumed = store_fuel_consumed; } + + // Fill the exit code in the execution result based on the next result: + // - Ok - execution passed, exit code is 0 (Ok) + // - InterruptionCalled - we don't know exit code since it's just an interruption + // - Err - an execution trap code (halts execution) match next_result { - Ok(_) => {} + Ok(_) => { + // Don't write exit code here, because it's managed by host functions + } Err(TrapCode::InterruptionCalled) => { - return self.handle_resumable_state(execution_result, ctx); + // We don't set exit code here, + // because exit code is used to represent identifier of call id } Err(err) => { execution_result.exit_code = ExitCode::from(err).into_i32(); } } - RuntimeResult::Result(execution_result) - } - /// Converts an in-flight interruption into a RuntimeResult::Interruption and prepares payload. - /// - /// Clears transient buffers, encodes the delegated invocation parameters, and packages the - /// suspended runtime for recovery by the root context. - fn handle_resumable_state( - &mut self, - execution_result: ExecutionResult, - ctx: &mut RuntimeContext, - ) -> RuntimeResult { - let ExecutionResult { - fuel_consumed, - fuel_refunded, - .. - } = execution_result; - // Take resumable context from execution context - let resumable_context = ctx.resumable_context.take().unwrap(); - if resumable_context.is_root { - unimplemented!("validate this logic, might not be ok in STF mode"); + // If the next result is interruption + if next_result == Err(TrapCode::InterruptionCalled) { + let ExecutionResult { + fuel_consumed, + fuel_refunded, + mut return_data, + .. + } = execution_result; + // A case for normal interruption (not system runtime interruption), where we should + // serialize the context we remembered inside `exec.rs` + // handler to pass into parent runtime. + // + // SAFETY: For system runtimes we don't save this + if let Some(resumable_return_data) = ctx.take_resumable_context_serialized() { + return_data = resumable_return_data; + } + return RuntimeResult::Interruption(ExecutionInterruption { + fuel_consumed, + fuel_refunded, + return_data, + }); } - // serialize the delegated execution state, - // but we don't serialize registers and stack state, - // instead we remember it inside the internal structure - // and assign a special identifier for recovery - let output = resumable_context.params.encode(); - RuntimeResult::Interruption(ExecutionInterruption { - fuel_consumed, - fuel_refunded, - output, - }) + + RuntimeResult::Result(execution_result) } } @@ -258,13 +263,13 @@ impl RuntimeExecutor for RuntimeFactoryExecutor { bytecode_or_hash: BytecodeOrHash, ctx: RuntimeContext, ) -> ExecutionResult { - #[cfg(feature = "wasmtime")] - let enable_wasmtime_runtime = match &bytecode_or_hash { - BytecodeOrHash::Bytecode { address, hash, .. } => { - fluentbase_types::is_execute_using_aot_compiler(address) - .then_some((*address, *hash)) - } - BytecodeOrHash::Hash(_) => None, + let (enable_wasmtime_runtime, enable_system_runtime) = match &bytecode_or_hash { + BytecodeOrHash::Bytecode { address, hash, .. } => ( + fluentbase_types::is_execute_using_wasmtime_strategy(address) + .then_some((*address, *hash)), + fluentbase_types::is_execute_using_system_runtime(address).then_some(*hash), + ), + BytecodeOrHash::Hash(_) => (None, None), }; // If we have a cached module, then use it, otherwise create a new one and cache @@ -274,33 +279,39 @@ impl RuntimeExecutor for RuntimeFactoryExecutor { let fuel_remaining = Some(ctx.fuel_limit); let fuel_config = FuelConfig::default().with_fuel_limit(ctx.fuel_limit); - #[cfg(feature = "wasmtime")] - let strategy = if let Some((address, code_hash)) = enable_wasmtime_runtime { - let module = self - .module_factory - .get_wasmtime_module_or_compile(code_hash, address); - Strategy::Wasmtime { module } + let mut exec_mode = if let Some(code_hash) = enable_system_runtime { + let runtime = SystemRuntime::new(module, self.import_linker.clone(), code_hash, ctx); + ExecutionMode::System(runtime) } else { - let engine = ExecutionEngine::acquire_shared(); - Strategy::Rwasm { module, engine } - }; - #[cfg(not(feature = "wasmtime"))] - let strategy = { - let engine = ExecutionEngine::acquire_shared(); - Strategy::Rwasm { module, engine } + #[cfg(feature = "wasmtime")] + let strategy = if let Some((address, code_hash)) = enable_wasmtime_runtime { + let module = self + .module_factory + .get_wasmtime_module_or_compile(code_hash, address); + Strategy::Wasmtime { module } + } else { + let engine = ExecutionEngine::acquire_shared(); + Strategy::Rwasm { module, engine } + }; + #[cfg(not(feature = "wasmtime"))] + let strategy = { + let engine = ExecutionEngine::acquire_shared(); + Strategy::Rwasm { module, engine } + }; + let runtime = RwasmRuntime::new(strategy, self.import_linker.clone(), ctx, fuel_config); + ExecutionMode::Rwasm(runtime) }; - let runtime = StrategyRuntime::new(strategy, self.import_linker.clone(), ctx, fuel_config); - let mut runtime = ExecutionMode::Strategy(runtime); - // Execute rWasm program - let result = runtime.execute(); - let fuel_consumed = runtime + // Execute program + let result = exec_mode.execute(); + let fuel_consumed = exec_mode .remaining_fuel() .zip(fuel_remaining) .map(|(remaining_fuel, store_fuel)| store_fuel - remaining_fuel); + let runtime_result = - runtime.context_mut(|ctx| self.handle_execution_result(result, fuel_consumed, ctx)); - self.try_remember_runtime(runtime_result, runtime) + exec_mode.context_mut(|ctx| self.handle_execution_result(result, fuel_consumed, ctx)); + self.try_remember_runtime(runtime_result, exec_mode) } fn resume( @@ -322,17 +333,13 @@ impl RuntimeExecutor for RuntimeFactoryExecutor { runtime.context_mut(|ctx| { ctx.execution_result.return_data = return_data.to_vec(); }); - // If we have fuel consumed greater than 0 then record it - if fuel_consumed > 0 { - runtime.try_consume_fuel(fuel_consumed)?; - } if fuel16_ptr > 0 { let mut buffer = [0u8; 16]; LittleEndian::write_u64(&mut buffer[..8], fuel_consumed); LittleEndian::write_i64(&mut buffer[8..], fuel_refunded); runtime.memory_write(fuel16_ptr as usize, &buffer)?; } - runtime.resume(exit_code) + runtime.resume(exit_code, fuel_consumed) }; let result = resume_inner(&mut runtime); // We need to adjust the fuel limit because `fuel_consumed` should not be included into spent. @@ -379,15 +386,33 @@ impl RuntimeExecutor for RuntimeFactoryExecutor { fn reset_call_id_counter(&mut self) { self.transaction_call_id_counter = 1; self.recoverable_runtimes.clear(); + self.recoverable_runtimes.clear(); + // Note: Ideally this shouldn't be required if there is no memory leaks, but supporting a + // memory allocator inside virtual runtime brings overhead. + // Instead, we can just re-create the store to make sure all data is pruned. + SystemRuntime::reset_cached_runtimes(); } -} + fn memory_read( + &mut self, + call_id: u32, + offset: usize, + buffer: &mut [u8], + ) -> Result<(), TrapCode> { + let runtime_ref = self.recoverable_runtimes.get_mut(&call_id).expect( + "runtime: missing recoverable runtime for memory read, this should never happen", + ); + runtime_ref.memory_read(offset, buffer) + } +} #[cfg(test)] mod tests { - use crate::executor::{ExecutionInterruption, RuntimeFactoryExecutor, RuntimeResult}; - use crate::runtime::ExecutionMode; - use crate::RuntimeContext; + use crate::{ + executor::{ExecutionInterruption, RuntimeFactoryExecutor, RuntimeResult}, + runtime::{ExecutionMode, RwasmRuntime}, + RuntimeContext, + }; use fluentbase_types::{import_linker_v1_preview, ExitCode}; use rwasm::{ExecutionEngine, FuelConfig, RwasmModule, Strategy}; @@ -401,7 +426,7 @@ mod tests { let interruption = RuntimeResult::Interruption(ExecutionInterruption { fuel_consumed: 100, fuel_refunded: 0, - output: vec![1, 2, 3], + return_data: vec![1, 2, 3], }); let engine = ExecutionEngine::acquire_shared(); @@ -409,13 +434,13 @@ mod tests { let ctx = RuntimeContext::default(); let fuel_config = FuelConfig::default(); - let strategy_runtime = crate::runtime::StrategyRuntime::new( + let strategy_runtime = RwasmRuntime::new( Strategy::Rwasm { module, engine }, executor.import_linker.clone(), ctx, fuel_config, ); - let runtime = ExecutionMode::Strategy(strategy_runtime); + let runtime = ExecutionMode::Rwasm(strategy_runtime); // Try to allocate call_id - should fail with overflow let result = executor.try_remember_runtime(interruption, runtime); @@ -426,5 +451,4 @@ mod tests { assert_eq!(result.fuel_refunded, 0); assert!(result.output.is_empty()); } - -} \ No newline at end of file +} diff --git a/crates/runtime/src/executor/global_executor.rs b/crates/runtime/src/executor/global_executor.rs index 1b0e7260e..a07685a01 100644 --- a/crates/runtime/src/executor/global_executor.rs +++ b/crates/runtime/src/executor/global_executor.rs @@ -2,8 +2,9 @@ use crate::{ executor::RuntimeFactoryExecutor, types::ExecutionResult, RuntimeContext, RuntimeExecutor, }; use fluentbase_types::{import_linker_v1_preview, Address, BytecodeOrHash, Bytes, B256}; -use rwasm::RwasmModule; +use rwasm::{RwasmModule, TrapCode}; use std::{ + ops::Range, panic, sync::{ mpsc::{sync_channel, Receiver, SyncSender}, @@ -154,6 +155,15 @@ impl RuntimeExecutor for GlobalExecutor { Err(panic_payload) => panic::resume_unwind(panic_payload), } } + + fn memory_read( + &mut self, + call_id: u32, + offset: usize, + buffer: &mut [u8], + ) -> Result<(), TrapCode> { + unimplemented!(); + } } fn runtime_thread(rx: Receiver) { diff --git a/crates/runtime/src/executor/local_executor.rs b/crates/runtime/src/executor/local_executor.rs index c4a5fda40..2ff5b35f1 100644 --- a/crates/runtime/src/executor/local_executor.rs +++ b/crates/runtime/src/executor/local_executor.rs @@ -3,7 +3,7 @@ use crate::{ RuntimeContext, RuntimeExecutor, }; use fluentbase_types::{import_linker_v1_preview, Address, BytecodeOrHash, B256}; -use rwasm::RwasmModule; +use rwasm::{RwasmModule, TrapCode}; use std::cell::RefCell; pub struct LocalExecutor; @@ -75,4 +75,15 @@ impl RuntimeExecutor for LocalExecutor { LOCAL_RUNTIME_EXECUTOR .with_borrow_mut(|runtime_executor| runtime_executor.reset_call_id_counter()) } + + fn memory_read( + &mut self, + call_id: u32, + offset: usize, + buffer: &mut [u8], + ) -> Result<(), TrapCode> { + LOCAL_RUNTIME_EXECUTOR.with_borrow_mut(|runtime_executor| { + runtime_executor.memory_read(call_id, offset, buffer) + }) + } } diff --git a/crates/runtime/src/runtime.rs b/crates/runtime/src/runtime.rs index 98c6f11e7..f5bb3728d 100644 --- a/crates/runtime/src/runtime.rs +++ b/crates/runtime/src/runtime.rs @@ -3,82 +3,62 @@ use rwasm::TrapCode; mod rwasm_runtime; pub use rwasm_runtime::*; -mod strategy_runtime; -pub use strategy_runtime::*; -#[cfg(feature = "wasmtime")] -mod wasmtime_runtime; -#[cfg(feature = "wasmtime")] -pub use wasmtime_runtime::*; +mod system_runtime; +pub use system_runtime::*; pub enum ExecutionMode { // TODO(dmitry123): Only this runtime is used for now, other remains for future optimizations. - Strategy(StrategyRuntime), Rwasm(RwasmRuntime), - #[cfg(feature = "wasmtime")] - Wasmtime(WasmtimeRuntime), + System(SystemRuntime), } impl ExecutionMode { pub fn execute(&mut self) -> Result<(), TrapCode> { match self { - ExecutionMode::Strategy(runtime) => runtime.execute(), ExecutionMode::Rwasm(runtime) => runtime.execute(), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.execute(), + ExecutionMode::System(runtime) => runtime.execute(), } } - pub fn resume(&mut self, exit_code: i32) -> Result<(), TrapCode> { + pub fn resume(&mut self, exit_code: i32, fuel_consumed: u64) -> Result<(), TrapCode> { match self { - ExecutionMode::Strategy(runtime) => runtime.resume(exit_code), - ExecutionMode::Rwasm(runtime) => runtime.resume(exit_code), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.resume(exit_code), + ExecutionMode::Rwasm(runtime) => runtime.resume(exit_code, fuel_consumed), + ExecutionMode::System(runtime) => runtime.resume(exit_code, fuel_consumed), } } - pub fn try_consume_fuel(&mut self, fuel: u64) -> Result<(), TrapCode> { + pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> { match self { - ExecutionMode::Strategy(runtime) => runtime.try_consume_fuel(fuel), - ExecutionMode::Rwasm(runtime) => runtime.try_consume_fuel(fuel), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.try_consume_fuel(fuel), + ExecutionMode::Rwasm(runtime) => runtime.memory_write(offset, data), + ExecutionMode::System(runtime) => runtime.memory_write(offset, data), } } - pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> { + pub fn memory_read(&mut self, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { match self { - ExecutionMode::Strategy(runtime) => runtime.memory_write(offset, data), - ExecutionMode::Rwasm(runtime) => runtime.memory_write(offset, data), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.memory_write(offset, data), + ExecutionMode::Rwasm(runtime) => runtime.memory_read(offset, buffer), + ExecutionMode::System(runtime) => runtime.memory_read(offset, buffer), } } pub fn remaining_fuel(&self) -> Option { match self { - ExecutionMode::Strategy(runtime) => runtime.remaining_fuel(), ExecutionMode::Rwasm(runtime) => runtime.remaining_fuel(), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.remaining_fuel(), + ExecutionMode::System(runtime) => runtime.remaining_fuel(), } } pub fn context_mut R>(&mut self, func: F) -> R { match self { - ExecutionMode::Strategy(runtime) => runtime.context_mut(func), ExecutionMode::Rwasm(runtime) => runtime.context_mut(func), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.context_mut(func), + ExecutionMode::System(runtime) => runtime.context_mut(func), } } pub fn context R>(&self, func: F) -> R { match self { - ExecutionMode::Strategy(runtime) => runtime.context(func), ExecutionMode::Rwasm(runtime) => runtime.context(func), - #[cfg(feature = "wasmtime")] - ExecutionMode::Wasmtime(runtime) => runtime.context(func), + ExecutionMode::System(runtime) => runtime.context(func), } } } diff --git a/crates/runtime/src/runtime/rwasm_runtime.rs b/crates/runtime/src/runtime/rwasm_runtime.rs index 7101c01e9..76c7a8b64 100644 --- a/crates/runtime/src/runtime/rwasm_runtime.rs +++ b/crates/runtime/src/runtime/rwasm_runtime.rs @@ -1,49 +1,51 @@ -use crate::context::RuntimeContext; -use rwasm::{ExecutionEngine, RwasmModule, RwasmStore, Store, TrapCode, Value}; +use crate::{syscall_handler::runtime_syscall_handler, RuntimeContext}; +use fluentbase_types::{STATE_DEPLOY, STATE_MAIN}; +use rwasm::{FuelConfig, ImportLinker, Store, Strategy, TrapCode, TypedStore, Value}; +use std::sync::Arc; -/// A compiled, executable runtime instance with its store and engine strategy. pub struct RwasmRuntime { - /// An engine for executing rWasm apps - pub engine: ExecutionEngine, - /// Underlying execution module. - pub module: RwasmModule, - /// Engine store carrying linear memory and the RuntimeContext. - pub store: RwasmStore, + strategy: Strategy, + store: TypedStore, + entrypoint: &'static str, } impl RwasmRuntime { - /// Creates a runtime from bytecode or code hash and initializes its store with the provided context. pub fn new( - engine: ExecutionEngine, - module: RwasmModule, - store: RwasmStore, + strategy: Strategy, + import_linker: Arc, + ctx: RuntimeContext, + fuel_config: FuelConfig, ) -> Self { + let entrypoint = match ctx.state { + STATE_MAIN => "main", + STATE_DEPLOY => "deploy", + _ => unreachable!(), + }; + let store = strategy.create_store(import_linker, ctx, runtime_syscall_handler, fuel_config); Self { - engine, - module, + strategy, store, + entrypoint, } } pub fn execute(&mut self) -> Result<(), TrapCode> { - self.engine - .execute(&mut self.store, &self.module, &[], &mut []) + self.strategy + .execute(&mut self.store, self.entrypoint, &[], &mut []) } - pub fn resume(&mut self, exit_code: i32) -> Result<(), TrapCode> { - self.engine.resume( - &mut self.store, - &[Value::I32(exit_code)], - &mut [], - ) + pub fn resume(&mut self, exit_code: i32, fuel_consumed: u64) -> Result<(), TrapCode> { + self.store.try_consume_fuel(fuel_consumed)?; + self.strategy + .resume(&mut self.store, &[Value::I32(exit_code)], &mut []) } pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> { self.store.memory_write(offset, data) } - pub fn try_consume_fuel(&mut self, fuel: u64) -> Result<(), TrapCode> { - self.store.try_consume_fuel(fuel) + pub fn memory_read(&mut self, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { + self.store.memory_read(offset, buffer) } pub fn remaining_fuel(&self) -> Option { diff --git a/crates/runtime/src/runtime/strategy_runtime.rs b/crates/runtime/src/runtime/strategy_runtime.rs deleted file mode 100644 index 31f0e6b02..000000000 --- a/crates/runtime/src/runtime/strategy_runtime.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{syscall_handler::runtime_syscall_handler, RuntimeContext}; -use fluentbase_types::{STATE_DEPLOY, STATE_MAIN}; -use rwasm::{FuelConfig, ImportLinker, Store, Strategy, TrapCode, TypedStore, Value}; -use std::sync::Arc; - -pub struct StrategyRuntime { - strategy: Strategy, - store: TypedStore, - entrypoint: &'static str, -} - -impl StrategyRuntime { - pub fn new( - strategy: Strategy, - import_linker: Arc, - ctx: RuntimeContext, - fuel_config: FuelConfig, - ) -> Self { - let entrypoint = match ctx.state { - STATE_MAIN => "main", - STATE_DEPLOY => "deploy", - _ => unreachable!(), - }; - let store = strategy.create_store(import_linker, ctx, runtime_syscall_handler, fuel_config); - Self { - strategy, - store, - entrypoint, - } - } - - pub fn execute(&mut self) -> Result<(), TrapCode> { - self.strategy - .execute(&mut self.store, self.entrypoint, &[], &mut []) - } - - pub fn resume(&mut self, exit_code: i32) -> Result<(), TrapCode> { - self.strategy - .resume(&mut self.store, &[Value::I32(exit_code)], &mut []) - } - - pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> { - self.store.memory_write(offset, data) - } - - #[must_use] - pub fn try_consume_fuel(&mut self, delta: u64) -> Result<(), TrapCode> { - self.store.try_consume_fuel(delta) - } - - pub fn remaining_fuel(&self) -> Option { - self.store.remaining_fuel() - } - - pub fn context_mut R>(&mut self, func: F) -> R { - self.store.context_mut(func) - } - - pub fn context R>(&self, func: F) -> R { - self.store.context(func) - } -} diff --git a/crates/runtime/src/runtime/wasmtime_runtime.rs b/crates/runtime/src/runtime/system_runtime.rs similarity index 51% rename from crates/runtime/src/runtime/wasmtime_runtime.rs rename to crates/runtime/src/runtime/system_runtime.rs index b7764568c..2ae4ea1d5 100644 --- a/crates/runtime/src/runtime/wasmtime_runtime.rs +++ b/crates/runtime/src/runtime/system_runtime.rs @@ -1,137 +1,233 @@ use crate::{syscall_handler::invoke_runtime_handler, RuntimeContext}; -use fluentbase_types::{Address, HashMap, SysFuncIdx, STATE_DEPLOY, STATE_MAIN}; -use rwasm::{ - ImportLinker, RwasmModule, Store, TrapCode, ValType, Value, F32, F64, N_MAX_STACK_SIZE, +use fluentbase_types::{ + ExitCode, HashMap, RuntimeInterruptionOutcomeV1, SysFuncIdx, B256, STATE_DEPLOY, STATE_MAIN, }; +use rwasm::{ImportLinker, RwasmModule, TrapCode, ValType, Value, F32, F64, N_MAX_STACK_SIZE}; use smallvec::SmallVec; use std::{ cell::RefCell, - sync::{Arc, OnceLock}, + mem::take, + rc::Rc, + sync::{Arc, OnceLock, RwLock}, }; use wasmtime::{ - AsContextMut, Config, Engine, Func, Instance, Linker, Module, OptLevel, Strategy, Trap, Val, + AsContextMut, Config, Engine, Func, Instance, Linker, Memory, Module, OptLevel, Store, + Strategy, Trap, Val, }; -pub struct WasmtimeRuntime { - compiled_runtime: Option, - ctx: Option, - address: Address, +pub struct SystemRuntime { + // TODO(dmitry123): We can't have compiled runtime because it makes the runtime no `no_std` complaint, + // it should be fixed once we have optimized wasmtime inside rwasm repository. + compiled_runtime: Rc>, + ctx: RuntimeContext, + code_hash: B256, + state: Option, } struct CompiledRuntime { module: Module, - store: wasmtime::Store, + store: Store, instance: Instance, + memory: Memory, deploy_func: Func, main_func: Func, - heap_reset_func: Func, } thread_local! { - pub static COMPILED_RUNTIMES: RefCell> = RefCell::new(HashMap::new()); + pub static COMPILED_RUNTIMES: RefCell>>> = RefCell::new(HashMap::new()); } -impl Drop for WasmtimeRuntime { - fn drop(&mut self) { - COMPILED_RUNTIMES.with_borrow_mut(|compiled_runtimes| { - compiled_runtimes.insert(self.address, self.compiled_runtime.take().unwrap()); - }); +impl SystemRuntime { + pub fn compiled_module(code_hash: B256, rwasm_module: RwasmModule) -> Module { + pub static COMPILED_MODULES: OnceLock>> = OnceLock::new(); + let compiled_modules = COMPILED_MODULES.get_or_init(|| RwLock::new(HashMap::new())); + { + let guard = compiled_modules.read().unwrap(); + if let Some(module) = guard.get(&code_hash) { + return module.clone(); + } + } + let mut guard = compiled_modules.write().unwrap(); + if let Some(module) = guard.get(&code_hash) { + return module.clone(); + } + let module = Module::new(wasmtime_engine(), &rwasm_module.hint_section).unwrap(); + guard.insert(code_hash, module.clone()); + module } -} -impl WasmtimeRuntime { - pub fn compile_module(rwasm_module: RwasmModule) -> Module { - Module::new(wasmtime_engine(), &rwasm_module.hint_section).unwrap() + pub fn reset_cached_runtimes() { + COMPILED_RUNTIMES.with_borrow_mut(|compiled_runtimes| { + compiled_runtimes.clear(); + }); } pub fn new( module: RwasmModule, import_linker: Arc, - address: Address, + code_hash: B256, ctx: RuntimeContext, ) -> Self { let compiled_runtime = COMPILED_RUNTIMES.with_borrow_mut(|compiled_runtimes| { - if let Some(compiled_runtime) = compiled_runtimes.remove(&address) { + if let Some(compiled_runtime) = compiled_runtimes.get(&code_hash).cloned() { return compiled_runtime; } - let module = Self::compile_module(module); + let module = Self::compiled_module(code_hash, module); let engine = wasmtime_engine(); let linker = wasmtime_import_linker(engine, import_linker); - let mut store = wasmtime::Store::new(engine, RuntimeContext::default()); + let mut store = Store::new(engine, RuntimeContext::default()); let instance = linker.instantiate(store.as_context_mut(), &module).unwrap(); let deploy_func = instance.get_func(store.as_context_mut(), "deploy").unwrap(); let main_func = instance.get_func(store.as_context_mut(), "main").unwrap(); - let heap_reset_func = instance - .get_func(store.as_context_mut(), "__heap_reset") + let memory = instance + .get_memory(store.as_context_mut(), "memory") .unwrap(); - CompiledRuntime { + let compiled_runtime = CompiledRuntime { module, store, instance, + memory, deploy_func, main_func, - heap_reset_func, - } + }; + let compiled_runtime = Rc::new(RefCell::new(compiled_runtime)); + compiled_runtimes.insert(code_hash, compiled_runtime.clone()); + compiled_runtime }); Self { - compiled_runtime: Some(compiled_runtime), - ctx: Some(ctx), - address, + compiled_runtime, + ctx, + code_hash, + state: None, } } pub fn execute(&mut self) -> Result<(), TrapCode> { - let compiled_runtime = self.compiled_runtime.as_mut().unwrap(); - // Rewrite heap base on every execution to release already used memory - compiled_runtime - .heap_reset_func - .call(compiled_runtime.store.as_context_mut(), &[], &mut []) - .unwrap(); - // Rewrite runtime context before each call - let ctx = self.ctx.take().unwrap(); - let entrypoint = match ctx.state { + let mut compiled_runtime = self.compiled_runtime.borrow_mut(); + + // Rewrite runtime context before each call, since we reuse the same store and runtime for + // all EVM/SVM contract calls, then we should replace an existing context. + // + // SAFETY: We always call execute/resume in "right" order (w/o call overlying) that makes + // calls sequential and apps can't access non-their context. + core::mem::swap(compiled_runtime.store.data_mut(), &mut self.ctx); + + // Call the function based on the passed state + let entrypoint = match compiled_runtime.store.data().state { STATE_MAIN => compiled_runtime.main_func, STATE_DEPLOY => compiled_runtime.deploy_func, _ => unreachable!(), }; - *compiled_runtime.store.data_mut() = ctx; - // Call the function based on the passed state - let result = entrypoint.call(compiled_runtime.store.as_context_mut(), &[], &mut []); - result.map_err(map_anyhow_error).or_else(|trap_code| { - if trap_code == TrapCode::ExecutionHalted { - Ok(()) - } else { - Err(trap_code) + let result = entrypoint + .call(compiled_runtime.store.as_context_mut(), &[], &mut []) + .map_err(map_anyhow_error); + + // Always swap back right after the call + core::mem::swap(compiled_runtime.store.data_mut(), &mut self.ctx); + + if let Err(trap_code) = result.as_ref() { + let exit_code = ExitCode::from(self.ctx.execution_result.exit_code); + if exit_code == ExitCode::Panic { + eprintln!( + "runtime: system execution failed with panic: {}, this should be investigated", + core::str::from_utf8(&self.ctx.execution_result.output) + .unwrap_or("can't decode utf-8 panic message") + ) + } else if exit_code != ExitCode::Ok { + eprintln!( + "runtime: system execution failed with exit code: {} ({}), this should be investigated", + exit_code, self.ctx.execution_result.exit_code + ) } - }) + eprintln!( + "runtime: an unexpected trap code happened inside system runtime: {:?} ({}), falling back to the unreachable code, this should be investigated", + trap_code, trap_code, + ); + return Err(TrapCode::UnreachableCodeReached); + } + + // System runtime returns output with exit code (as first four bytes). + // It doesn't halt, because halt or trap doesn't unwind the stack properly. + let output = take(&mut self.ctx.execution_result.output); + if output.len() < 4 { + eprintln!( + "runtime: an unexpected output size returned from system runtime: {}, falling back to the unreachable code, this should be investigated", + output.len() + ); + return Err(TrapCode::UnreachableCodeReached); + } + let (exit_code_le, output) = output.split_at(4); + self.ctx.execution_result.output = output.to_vec(); + let exit_code = i32::from_le_bytes(exit_code_le.try_into().unwrap()); + self.ctx.execution_result.exit_code = exit_code; + + // If the execution result is `InterruptionCalled`, then interruption is called, we should re-map + // trap code into an interruption. + // + // SAFETY: Exit code `InterruptionCalled` can only be passed by our system runtimes, trustless + // applications can use this error code, but it won't be handled because of different + // runtime (only punishment for halt exit code). + if ExitCode::from_repr(exit_code) == Some(ExitCode::InterruptionCalled) { + // We need to move output into return data, because in our common case, interruptions + // store syscall params inside return data, + // but we can't suppose this for system runtime contracts because we don't expose such + // functions, that's why we should move data from output into return data + self.ctx.execution_result.return_data = take(&mut self.ctx.execution_result.output); + assert!( + !self.ctx.execution_result.return_data.is_empty(), + "runtime: output can't be empty for interrupted call" + ); + // Initialize resumable context with empty parameters, these values are passed into + // the resume function once we're ready to resume + self.state = Some(RuntimeInterruptionOutcomeV1::default()); + return Err(TrapCode::InterruptionCalled); + } + + result } - pub fn try_consume_fuel(&mut self, _fuel: u64) -> Result<(), TrapCode> { - // We don't support fuel for this runtime - Ok(()) + pub fn resume(&mut self, _exit_code: i32, _fuel_consumed: u64) -> Result<(), TrapCode> { + // Make sure the runtime is always clear before resuming the call, because output is used + // to pass interruption params in case of interruption + self.ctx.clear_output(); + + // Since we don't suppose native interruptions inside system runtimes then we just re-call + // execute, but with passed return data with interruption outcome. + // + // Possible scenarios: + // 1. w/ return data - new frame call + // 2. w/o return data - current frame interruption outcome + self.execute() } - pub fn memory_write(&mut self, _offset: usize, _data: &[u8]) -> Result<(), TrapCode> { - unimplemented!() + pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> { + let mut compiled_runtime = self.compiled_runtime.borrow_mut(); + let memory = compiled_runtime.memory; + memory + .write(&mut compiled_runtime.store, offset, data) + .map_err(|_| TrapCode::MemoryOutOfBounds) + } + + pub fn memory_read(&mut self, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { + let compiled_runtime = self.compiled_runtime.borrow(); + compiled_runtime + .memory + .read(&compiled_runtime.store, offset, buffer) + .map_err(|_| TrapCode::MemoryOutOfBounds) } pub fn remaining_fuel(&self) -> Option { - // We don't support fuel for this runtime + // We don't return the remaining fuel here because we don't know the remaining fuel, + // also system runtime only used for trusted smart contracts with self gas management None } pub fn context_mut R>(&mut self, func: F) -> R { - let compiled_runtime = self.compiled_runtime.as_mut().unwrap(); - func(compiled_runtime.store.data_mut()) + func(&mut self.ctx) } pub fn context R>(&self, func: F) -> R { - let compiled_runtime = self.compiled_runtime.as_ref().unwrap(); - func(compiled_runtime.store.data()) - } - - pub fn resume(&mut self, _exit_code: i32) -> Result<(), TrapCode> { - unreachable!() + func(&self.ctx) } } @@ -145,7 +241,7 @@ fn wasmtime_engine() -> &'static Engine { cfg.async_support(false); cfg.wasm_memory64(false); cfg.memory_init_cow(false); - cfg.cranelift_opt_level(OptLevel::SpeedAndSize); + cfg.cranelift_opt_level(OptLevel::Speed); cfg.parallel_compilation(true); cfg.consume_fuel(false); let engine = Engine::new(&cfg).unwrap(); @@ -155,10 +251,9 @@ fn wasmtime_engine() -> &'static Engine { struct CallerAdapter<'a> { caller: wasmtime::Caller<'a, RuntimeContext>, - fuel_consumed: u64, } -impl<'a> Store for CallerAdapter<'a> { +impl<'a> rwasm::Store for CallerAdapter<'a> { fn memory_read(&mut self, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> { let memory = self .caller @@ -191,13 +286,14 @@ impl<'a> Store for CallerAdapter<'a> { func(self.caller.data()) } - fn try_consume_fuel(&mut self, delta: u64) -> Result<(), TrapCode> { - self.fuel_consumed += delta; + fn try_consume_fuel(&mut self, _delta: u64) -> Result<(), TrapCode> { + // There is no need to count this, we already have this counted inside the context Ok(()) } fn remaining_fuel(&self) -> Option { - None + let ctx = self.caller.data(); + Some(ctx.fuel_limit - ctx.execution_result.fuel_consumed) } } @@ -249,13 +345,10 @@ fn wasmtime_syscall_handler<'a>( Val::F64(value) => Value::F64(F64::from_bits(*value)), _ => unreachable!("wasmtime: not supported type: {:?}", x), })); - buffer.extend(std::iter::repeat(Value::I32(0)).take(result.len())); + buffer.extend(core::iter::repeat(Value::I32(0)).take(result.len())); let (mapped_params, mapped_result) = buffer.split_at_mut(params.len()); // caller adapter is required to provide operations for accessing memory and context - let mut caller_adapter = CallerAdapter::<'a> { - caller, - fuel_consumed: 0, - }; + let mut caller_adapter = CallerAdapter::<'a> { caller }; let sys_func_idx = SysFuncIdx::from_repr(sys_func_idx).ok_or(TrapCode::UnknownExternalFunction)?; let syscall_result = invoke_runtime_handler( @@ -264,12 +357,6 @@ fn wasmtime_syscall_handler<'a>( mapped_params, mapped_result, ); - match syscall_result { - Err(TrapCode::InterruptionCalled) => { - unreachable!("interruptions are not allowed") - } - _ => {} - } // make sure a syscall result is successful let should_terminate = syscall_result.map(|_| false).or_else(|trap_code| { // if syscall returns execution halted, @@ -299,6 +386,7 @@ fn wasmtime_syscall_handler<'a>( fn map_anyhow_error(err: anyhow::Error) -> TrapCode { if let Some(trap) = err.downcast_ref::() { + eprintln!("wasmtime trap code: {:?}", trap); // map wasmtime trap codes into our trap codes use wasmtime::Trap; match trap { @@ -312,7 +400,7 @@ fn map_anyhow_error(err: anyhow::Error) -> TrapCode { Trap::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, Trap::BadConversionToInteger => TrapCode::BadConversionToInteger, Trap::UnreachableCodeReached => TrapCode::UnreachableCodeReached, - Trap::Interrupt => unreachable!("interrupt is not supported"), + Trap::Interrupt => TrapCode::InterruptionCalled, Trap::AlwaysTrapAdapter => unreachable!("component-model is not supported"), Trap::OutOfFuel => TrapCode::OutOfFuel, Trap::AtomicWaitNonSharedMemory => { @@ -331,7 +419,7 @@ fn map_anyhow_error(err: anyhow::Error) -> TrapCode { // if our trap code is initiated, then just return the trap code *trap } else { - eprintln!("wasmtime unknown trap: {:?}", err); + eprintln!("wasmtime: unknown trap: {:?}", err); // TODO(dmitry123): "what type of error to use here in case of unknown error?" TrapCode::IllegalOpcode } diff --git a/crates/runtime/src/syscall_handler/host/debug_log.rs b/crates/runtime/src/syscall_handler/host/debug_log.rs index 1145081b2..c2cc37c68 100644 --- a/crates/runtime/src/syscall_handler/host/debug_log.rs +++ b/crates/runtime/src/syscall_handler/host/debug_log.rs @@ -35,9 +35,9 @@ pub fn syscall_debug_log_impl(msg: &[u8]) { 0 }; LAST_LOG_TIME.set(curr_time); - const MSG_LIMIT: usize = 256000; - let msg = if msg.len() > MSG_LIMIT { - &msg[..MSG_LIMIT] + const DEBUG_LOG_MAXIMUM_LEN: usize = 1_000; + let msg = if msg.len() > DEBUG_LOG_MAXIMUM_LEN { + &msg[..DEBUG_LOG_MAXIMUM_LEN] } else { &msg[..] }; diff --git a/crates/runtime/src/syscall_handler/host/exec.rs b/crates/runtime/src/syscall_handler/host/exec.rs index e343921a2..1f023a676 100644 --- a/crates/runtime/src/syscall_handler/host/exec.rs +++ b/crates/runtime/src/syscall_handler/host/exec.rs @@ -5,7 +5,7 @@ use crate::{ }; use fluentbase_types::{ byteorder::{ByteOrder, LittleEndian}, - BytecodeOrHash, Bytes, BytesOrRef, ExitCode, SyscallInvocationParams, B256, CALL_STACK_LIMIT, + BytecodeOrHash, BytesOrRef, ExitCode, SyscallInvocationParams, B256, CALL_STACK_LIMIT, }; use rwasm::{Store, TrapCode, Value}; use std::{ @@ -65,13 +65,10 @@ pub fn syscall_exec_handler( let mut code_hash = [0u8; 32]; caller.memory_read(hash32_ptr, &mut code_hash)?; let code_hash = B256::from(code_hash); - let mut input = vec![0u8; input_len]; - caller.memory_read(input_ptr, &mut input)?; - let input = Bytes::from(input); let is_root = caller.context(|ctx| ctx.call_depth) == 0; let params = SyscallInvocationParams { code_hash, - input, + input: input_ptr..(input_ptr + input_len), fuel_limit, state, fuel16_ptr: fuel16_ptr as u32, @@ -83,20 +80,21 @@ pub fn syscall_exec_handler( /// Continues an exec after an interruption, executing the delegated call. pub fn syscall_exec_continue( - caller: &mut impl Store, - context: &InterruptionHolder, + _caller: &mut impl Store, + _context: &InterruptionHolder, ) -> (u64, i64, i32) { - let fuel_limit = context.params.fuel_limit; - let (fuel_consumed, fuel_refunded, exit_code) = caller.context_mut(|ctx| { - syscall_exec_impl( - ctx, - context.params.code_hash, - BytesOrRef::Ref(context.params.input.as_ref()), - fuel_limit, - context.params.state, - ) - }); - (fuel_consumed, fuel_refunded, exit_code) + unimplemented!("runtime: not supported until we finish zkVM"); + // let fuel_limit = context.params.fuel_limit; + // let (fuel_consumed, fuel_refunded, exit_code) = caller.context_mut(|ctx| { + // syscall_exec_impl( + // ctx, + // context.params.code_hash, + // BytesOrRef::Ref(context.params.input.as_ref()), + // fuel_limit, + // context.params.state, + // ) + // }); + // (fuel_consumed, fuel_refunded, exit_code) } /// Executes a nested runtime with the given parameters and merges the result into ctx. diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index a94e4c027..785597110 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -21,6 +21,8 @@ hashbrown = { workspace = true } auto_impl = { workspace = true } bincode = { workspace = true } +spin = { version = "0.10.0", default-features = false, features = ["mutex"] } + [dev-dependencies] hex-literal = { workspace = true } diff --git a/crates/sdk/src/allocator.rs b/crates/sdk/src/allocator.rs index 19c81cb0a..d027856a5 100644 --- a/crates/sdk/src/allocator.rs +++ b/crates/sdk/src/allocator.rs @@ -3,13 +3,13 @@ use alloc::vec::Vec; const WASM_PAGE_SIZE_IN_BYTES: usize = 65536; #[allow(dead_code)] -fn calc_pages_needed(pages_allocated: usize, ptr: usize) -> usize { - let current_memory = pages_allocated * WASM_PAGE_SIZE_IN_BYTES; - if ptr >= current_memory { - (current_memory + ptr + 1 + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES - - pages_allocated - } else { +fn calc_pages_needed(pages_allocated: usize, required_bytes: usize) -> usize { + let have = pages_allocated * WASM_PAGE_SIZE_IN_BYTES; + if required_bytes <= have { 0 + } else { + let missing = required_bytes - have; + (missing + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES } } @@ -17,16 +17,16 @@ fn calc_pages_needed(pages_allocated: usize, ptr: usize) -> usize { fn test_pages_needed() { assert_eq!(calc_pages_needed(0, 1), 1); assert_eq!(calc_pages_needed(0, 65535), 1); - assert_eq!(calc_pages_needed(0, 65536), 2); - assert_eq!(calc_pages_needed(1, 65536), 2); + assert_eq!(calc_pages_needed(0, 65536), 1); + assert_eq!(calc_pages_needed(1, 65536), 0); assert_eq!(calc_pages_needed(1, 65535), 0); - assert_eq!(calc_pages_needed(1, 65536 * 2), 3); - assert_eq!(calc_pages_needed(5, 327680), 6); + assert_eq!(calc_pages_needed(1, 65536 + 65536), 1); + assert_eq!(calc_pages_needed(5, 327680), 0); } #[inline(always)] pub fn alloc_ptr(len: usize) -> *mut u8 { - unsafe { alloc::alloc::alloc(core::alloc::Layout::from_size_align_unchecked(len, 8)) } + unsafe { alloc::alloc::alloc_zeroed(core::alloc::Layout::from_size_align_unchecked(len, 8)) } } #[inline(always)] @@ -46,6 +46,26 @@ pub struct HeapBaseAllocator {} #[cfg(target_arch = "wasm32")] static mut HEAP_POS: usize = 0; +#[inline(always)] +pub fn alloc_heap_pos() -> usize { + #[cfg(target_arch = "wasm32")] + unsafe { + HEAP_POS + } + #[cfg(not(target_arch = "wasm32"))] + { + usize::MAX + } +} + +#[inline(always)] +pub fn rollback_heap_pos(_new_heap_pos: usize) { + #[cfg(target_arch = "wasm32")] + unsafe { + HEAP_POS = _new_heap_pos + } +} + #[cfg(target_arch = "wasm32")] unsafe impl core::alloc::GlobalAlloc for HeapBaseAllocator { #[inline(never)] @@ -61,7 +81,7 @@ unsafe impl core::alloc::GlobalAlloc for HeapBaseAllocator { } let offset = heap_pos & (align - 1); if offset != 0 { - heap_pos += align - offset; + heap_pos = heap_pos.wrapping_add(align - offset); } // allocate memory pages if needed let pages_allocated = core::arch::wasm32::memory_size::<0>(); @@ -90,10 +110,11 @@ unsafe impl core::alloc::GlobalAlloc for HeapBaseAllocator { #[cfg(target_arch = "wasm32")] #[no_mangle] -pub extern "C" fn __heap_reset() { +pub extern "C" fn __heap_pos() -> usize { extern "C" { static __heap_base: u8; } let mut heap_pos = unsafe { HEAP_POS }; heap_pos = unsafe { (&__heap_base) as *const u8 as usize }; + heap_pos } diff --git a/crates/sdk/src/debug.rs b/crates/sdk/src/debug.rs new file mode 100644 index 000000000..23a87d552 --- /dev/null +++ b/crates/sdk/src/debug.rs @@ -0,0 +1,285 @@ +use core::fmt::{self, Write as _}; + +pub const DEBUG_LOG_MAXIMUM_LEN: usize = 1_000; + +#[cfg(target_arch = "wasm32")] +struct SyncUnsafeCell(core::cell::UnsafeCell); + +#[cfg(target_arch = "wasm32")] +impl SyncUnsafeCell { + const fn new(v: T) -> Self { + Self(core::cell::UnsafeCell::new(v)) + } + #[inline] + fn get(&self) -> *mut T { + self.0.get() + } +} + +#[cfg(target_arch = "wasm32")] +unsafe impl Sync for SyncUnsafeCell {} + +#[cfg(target_arch = "wasm32")] +static BUF: SyncUnsafeCell<[u8; DEBUG_LOG_MAXIMUM_LEN]> = + SyncUnsafeCell::new([0; DEBUG_LOG_MAXIMUM_LEN]); + +#[cfg(not(target_arch = "wasm32"))] +static BUF: std::sync::Mutex<[u8; DEBUG_LOG_MAXIMUM_LEN]> = + std::sync::Mutex::new([0; DEBUG_LOG_MAXIMUM_LEN]); + +struct SliceWriter<'a> { + buf: &'a mut [u8], + len: usize, + truncated: bool, +} +impl<'a> SliceWriter<'a> { + #[inline] + fn new(buf: &'a mut [u8]) -> Self { + Self { + buf, + len: 0, + truncated: false, + } + } + #[inline] + fn as_bytes(&self) -> &[u8] { + &self.buf[..self.len] + } + #[inline] + fn as_str(&self) -> &str { + core::str::from_utf8(self.as_bytes()).unwrap() + } +} + +impl fmt::Write for SliceWriter<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let space = self.buf.len().saturating_sub(self.len); + if s.len() <= space { + self.buf[self.len..self.len + s.len()].copy_from_slice(s.as_bytes()); + self.len += s.len(); + } else { + let take = space; + if take > 0 { + self.buf[self.len..self.len + take].copy_from_slice(&s.as_bytes()[..take]); + self.len += take; + } + self.truncated = true; + } + Ok(()) + } +} + +pub const fn two_component_start(path: &'static str) -> usize { + let bytes = path.as_bytes(); + let mut i = bytes.len(); + let mut count = 0usize; + while i > 0 { + i -= 1; + if bytes[i] == b'/' || bytes[i] == b'\\' { + count += 1; + if count == 2 { + return i + 1; + } + } + } + 0 +} +#[inline] +pub fn short_file(path: &'static str) -> &'static str { + &path[two_component_start(path)..] +} + +/// Returns (start_index, end_index) of the function name inside `full`. +pub const fn fn_name_bounds(full: &'static str) -> (usize, usize) { + let bytes = full.as_bytes(); + let mut len = bytes.len(); + + // Remove trailing "::{{closure...}}" suffix if present + // Find the substring start of "::{{closure" + let mut i = 0usize; + while i + 10 <= len { + // "::{{closure" length = 10 chars + // manual compare because const fn can't use `starts_with` + let mut match_closure = true; + let spec = b"::{{closure"; + let mut j = 0usize; + while j < spec.len() { + if bytes[i + j] != spec[j] { + match_closure = false; + break; + } + j += 1; + } + if match_closure { + len = i; // cut suffix + break; + } + i += 1; + } + + // Now find last "::" *outside* generics <...> + let mut depth = 0i32; + let mut start = 0usize; + let mut k = len; + while k > 1 { + k -= 1; + let b = bytes[k]; + if b == b'>' { + depth += 1; + } else if b == b'<' { + if depth > 0 { + depth -= 1; + } + } else if b == b':' && bytes[k - 1] == b':' && depth == 0 { + start = k + 1; // after "::" + break; + } + } + + // Strip trailing generics: find first '<' after start + let mut end = len; + let mut d2 = 0i32; + let mut j2 = start; + while j2 < len { + let b = bytes[j2]; + if b == b'<' && d2 == 0 { + end = j2; + break; + } + if b == b'<' { + d2 += 1; + } else if b == b'>' && d2 > 0 { + d2 -= 1; + } + j2 += 1; + } + + (start, end) +} + +/// Extract the caller function name from a type-name string like: +/// fluentbase_contracts_evm::main_entry<...>::{{closure}} +/// Returns: "main_entry" +#[inline] +pub fn extract_fn_name(full: &'static str) -> &'static str { + let (start, end) = fn_name_bounds(full); + &full[start..end] +} + +pub fn debug_log_write_with_loc( + file: &'static str, + line: u32, + func: &'static str, + args: fmt::Arguments<'_>, +) -> Result<(), fmt::Error> { + #[cfg(target_arch = "wasm32")] + let w: &mut [u8] = unsafe { &mut *BUF.get() }; + #[cfg(not(target_arch = "wasm32"))] + let mut w_guard = BUF.lock().unwrap(); + #[cfg(not(target_arch = "wasm32"))] + let w = w_guard.as_mut_slice(); + + let mut w = SliceWriter::new(w); + + // prefix + write!(&mut w, "[{}:{} {}] ", short_file(file), line, func)?; + w.write_fmt(args)?; + + // If truncated → append "..." + if w.truncated { + let remaining = w.buf.len().saturating_sub(w.len); + if remaining >= 3 { + // enough space → append + w.buf[w.len..w.len + 3].copy_from_slice(b"..."); + w.len += 3; + } else if w.buf.len() >= 3 { + // not enough → overwrite last 3 bytes + let end = w.buf.len(); + w.buf[end - 3..end].copy_from_slice(b"..."); + w.len = end; + } + } + + #[cfg(target_arch = "wasm32")] + unsafe { + #[link(wasm_import_module = "fluentbase_v1preview")] + extern "C" { + fn _debug_log(ptr: *const u8, len: u32); + } + let b = w.as_bytes(); + _debug_log(b.as_ptr(), b.len() as u32); + } + + #[cfg(feature = "std")] + { + println!("{}", w.as_str()); + } + + Ok(()) +} + +#[cfg(debug_assertions)] +#[macro_export] +macro_rules! debug_log { + () => {{ + let _ = $crate::debug::debug_log_write_with_loc( + $crate::debug::short_file(file!()), + line!(), + $crate::debug::extract_fn_name(core::any::type_name_of_val(&|| {})), + core::format_args!(""), + ); + }}; + ($msg:expr) => {{ + let _ = $crate::debug::debug_log_write_with_loc( + $crate::debug::short_file(file!()), + line!(), + $crate::debug::extract_fn_name(core::any::type_name_of_val(&|| {})), + core::format_args!($msg), + ); + }}; + ($($arg:tt)*) => {{ + let _ = $crate::debug::debug_log_write_with_loc( + $crate::debug::short_file(file!()), + line!(), + $crate::debug::extract_fn_name(core::any::type_name_of_val(&|| {})), + core::format_args!($($arg)*), + ); + }}; +} + +#[cfg(not(debug_assertions))] +#[macro_export] +macro_rules! debug_log { + () => {{}}; + ($msg:expr) => {{}}; + ($($arg:tt)*) => {{}}; +} + +#[cfg(test)] +mod tests { + use super::*; + use core::any; + + #[test] + fn short_file_last_two_components() { + assert_eq!(short_file("a/b/c/d.rs"), "c/d.rs"); + assert_eq!(short_file("foo/bar.rs"), "foo/bar.rs"); + assert_eq!(short_file("mod.rs"), "mod.rs"); + } + + #[test] + fn extract_fn_name_from_closure_typename() { + assert_eq!( + extract_fn_name(any::type_name_of_val(&|| {})), + "extract_fn_name_from_closure_typename" + ); + } + + #[test] + fn extract_fn_generic() { + assert_eq!( + extract_fn_name("fluentbase_contracts_evm::main_entry>::{{closure}}"), + "main_entry" + ); + } +} diff --git a/crates/sdk/src/entrypoint.rs b/crates/sdk/src/entrypoint.rs index c89aad693..59158c4d6 100644 --- a/crates/sdk/src/entrypoint.rs +++ b/crates/sdk/src/entrypoint.rs @@ -54,7 +54,7 @@ macro_rules! entrypoint_with_storage { } #[macro_export] -macro_rules! func_entrypoint { +macro_rules! define_entrypoint { ($main_func:ident, $deploy_func:ident) => { #[cfg(target_arch = "wasm32")] mod _fluentbase_entrypoint { @@ -79,8 +79,6 @@ macro_rules! func_entrypoint { let sdk = SharedContextImpl::new(RwasmContext {}); __deploy_entry(sdk); } - $crate::define_panic_handler!(); - $crate::define_allocator!(); } }; ($main_func:ident) => { @@ -99,12 +97,24 @@ macro_rules! func_entrypoint { } #[no_mangle] extern "C" fn deploy() {} - $crate::define_panic_handler!(); - $crate::define_allocator!(); } }; } +#[macro_export] +macro_rules! func_entrypoint { + ($main_func:ident, $deploy_func:ident) => { + $crate::define_entrypoint!($main_func, $deploy_func); + $crate::define_panic_handler!(); + $crate::define_allocator!(); + }; + ($main_func:ident) => { + $crate::define_entrypoint!($main_func); + $crate::define_panic_handler!(); + $crate::define_allocator!(); + }; +} + #[macro_export] macro_rules! entrypoint { ($main_func:ident, $deploy_func:ident) => { @@ -118,3 +128,88 @@ macro_rules! entrypoint { fn main() {} }; } + +#[macro_export] +macro_rules! system_entrypoint { + ($main_func:ident, $deploy_func:ident) => { + #[cfg(target_arch = "wasm32")] + mod _fluentbase_entrypoint { + use alloc::vec::Vec; + use $crate::{byteorder, byteorder::ByteOrder, Bytes, ExitCode, SharedAPI}; + #[inline(always)] + fn __main_entry(mut sdk: impl SharedAPI) { + let (output, exit_code) = match super::$main_func(&mut sdk) { + Ok(output) => (output, ExitCode::Ok), + Err(exit_code) => (Bytes::new(), exit_code), + }; + let mut exit_code_le: [u8; 4] = [0u8; 4]; + byteorder::LE::write_i32(&mut exit_code_le, exit_code as i32); + let mut result = Vec::with_capacity(4 + output.len()); + result.extend_from_slice(&exit_code_le); + result.extend_from_slice(&output); + sdk.write(&result); + } + #[inline(always)] + fn __deploy_entry(mut sdk: impl SharedAPI) { + let (output, exit_code) = match super::$deploy_func(&mut sdk) { + Ok(output) => (output, ExitCode::Ok), + Err(exit_code) => (Bytes::new(), exit_code), + }; + let mut exit_code_le: [u8; 4] = [0u8; 4]; + byteorder::LE::write_i32(&mut exit_code_le, exit_code as i32); + let mut result = Vec::with_capacity(4 + output.len()); + result.extend_from_slice(&exit_code_le); + result.extend_from_slice(&output); + sdk.write(&result); + } + #[no_mangle] + extern "C" fn main() { + use fluentbase_sdk::{shared::SharedContextImpl, RwasmContext}; + let sdk = SharedContextImpl::new(RwasmContext {}); + __main_entry(sdk); + } + #[no_mangle] + extern "C" fn deploy() { + use fluentbase_sdk::{shared::SharedContextImpl, RwasmContext}; + let sdk = SharedContextImpl::new(RwasmContext {}); + __deploy_entry(sdk); + } + } + $crate::define_panic_handler!(); + $crate::define_allocator!(); + #[cfg(not(target_arch = "wasm32"))] + fn main() {} + }; + ($main_func:ident) => { + #[cfg(target_arch = "wasm32")] + mod _fluentbase_entrypoint { + use alloc::vec::Vec; + use $crate::{byteorder, byteorder::ByteOrder, Bytes, ExitCode, SharedAPI}; + #[inline(always)] + fn __main_entry(mut sdk: impl SharedAPI) { + let (output, exit_code) = match super::$main_func(&mut sdk) { + Ok(output) => (output, ExitCode::Ok), + Err(exit_code) => (Bytes::new(), exit_code), + }; + let mut exit_code_le: [u8; 4] = [0u8; 4]; + byteorder::LE::write_i32(&mut exit_code_le, exit_code as i32); + let mut result = Vec::with_capacity(4 + output.len()); + result.extend_from_slice(&exit_code_le); + result.extend_from_slice(&output); + sdk.write(&result); + } + #[no_mangle] + extern "C" fn main() { + use fluentbase_sdk::{shared::SharedContextImpl, RwasmContext}; + let sdk = SharedContextImpl::new(RwasmContext {}); + __main_entry(sdk); + } + #[no_mangle] + extern "C" fn deploy() {} + } + $crate::define_panic_handler!(); + $crate::define_allocator!(); + #[cfg(not(target_arch = "wasm32"))] + fn main() {} + }; +} diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 6e9812996..08d385dc6 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -8,6 +8,7 @@ pub extern crate rwasm as rwasm_core; mod address; mod allocator; pub mod constructor; +pub mod debug; pub mod entrypoint; pub mod leb128; mod macros; diff --git a/crates/sdk/src/macros.rs b/crates/sdk/src/macros.rs index b6de2c458..573a2f0f5 100644 --- a/crates/sdk/src/macros.rs +++ b/crates/sdk/src/macros.rs @@ -1,67 +1,3 @@ -#[macro_export] -macro_rules! this_function_path { - () => {{ - fn f() {} - fn type_name_of(_: T) -> &'static str { - core::any::type_name::() - } - let name = type_name_of(f); - name.strip_suffix("::f").unwrap() - }}; -} -#[macro_export] -macro_rules! current_line_info { - () => {{ - alloc::format!("{}:{}", $crate::this_function_path!(), core::line!()) - }}; -} - -#[macro_export] -macro_rules! debug_log { - ($msg:tt) => {{ - #[cfg(target_arch = "wasm32")] - { - #[link(wasm_import_module = "fluentbase_v1preview")] - extern "C" { - pub fn _debug_log(msg_ptr: *const u8, msg_len: u32); - } - unsafe { _debug_log($msg.as_ptr(), $msg.len() as u32) } - } - #[cfg(feature = "std")] - println!("{}", $msg); - }}; - ($($arg:tt)*) => {{ - let msg = alloc::format!($($arg)*); - $crate::debug_log!(msg); - }}; -} - -#[macro_export] -macro_rules! debug_log_ext { - () => {{ - $crate::debug_log_ext!(""); - }}; - ($msg:tt) => {{ - extern crate alloc; - let msg = alloc::format!("{}: {}", $crate::current_line_info!(), $msg); - #[cfg(target_arch = "wasm32")] - { - #[link(wasm_import_module = "fluentbase_v1preview")] - extern "C" { - pub fn _debug_log(msg_ptr: *const u8, msg_len: u32); - } - unsafe { _debug_log(msg.as_ptr(), msg.len() as u32) } - } - #[cfg(feature = "std")] - println!("{}", msg); - }}; - ($($arg:tt)*) => {{ - extern crate alloc; - let msg = alloc::format!($($arg)*); - $crate::debug_log_ext!(msg); - }}; -} - #[macro_export] macro_rules! define_allocator { () => { diff --git a/crates/sdk/src/syscall.rs b/crates/sdk/src/syscall.rs index 97fee51a5..608f7aa7b 100644 --- a/crates/sdk/src/syscall.rs +++ b/crates/sdk/src/syscall.rs @@ -242,7 +242,7 @@ impl SyscallInterruptExecutor for T { fn self_balance(&self) -> (u64, i64, i32) { self.interrupt( BytecodeOrHash::Hash(SYSCALL_ID_SELF_BALANCE), - Default::default(), + &[], None, STATE_MAIN, ) diff --git a/crates/sdk/src/types/context.rs b/crates/sdk/src/types/context.rs index 16e88cc63..ac1670616 100644 --- a/crates/sdk/src/types/context.rs +++ b/crates/sdk/src/types/context.rs @@ -1,4 +1,5 @@ use auto_impl::auto_impl; +use bincode::config::{Configuration, Fixint, LittleEndian}; use fluentbase_types::{Address, Bytes, B256, U256}; #[auto_impl(&)] @@ -25,6 +26,8 @@ pub trait ContextReader { fn contract_gas_limit(&self) -> u64; } +const BINCODE_CONFIG_DEFAULT: Configuration = bincode::config::legacy(); + #[derive(Clone, Debug, PartialEq)] pub enum SharedContextInput { V1(SharedContextInputV1), @@ -32,16 +35,14 @@ pub enum SharedContextInput { impl SharedContextInput { pub fn decode(buf: &[u8]) -> Result { - let config = bincode::config::legacy(); - let result = bincode::decode_from_slice(buf, config)?; + let result = bincode::decode_from_slice(buf, BINCODE_CONFIG_DEFAULT)?; Ok(Self::V1(result.0)) } pub fn encode(&self) -> Result { match self { SharedContextInput::V1(value) => { - let config = bincode::config::legacy(); - let result: Bytes = bincode::encode_to_vec(value, config)?.into(); + let result: Bytes = bincode::encode_to_vec(value, BINCODE_CONFIG_DEFAULT)?.into(); Ok(result) } } @@ -226,8 +227,9 @@ impl bincode::Encode for SharedContextInputV1 { bincode::Encode::encode(&contract_value, e)?; bincode::Encode::encode(&contract_gas_limit, e)?; - let reserved = [0u8; 642]; // Use this space to add new fields in the future + let reserved = [0u8; Self::SIZE_RESERVED]; bincode::Encode::encode(&reserved, e)?; + Ok(()) } } @@ -260,6 +262,9 @@ impl bincode::Decode for SharedContextInputV1 { let contract_value: [u8; 32] = bincode::Decode::decode(d)?; let contract_gas_limit = bincode::Decode::decode(d)?; + // Skip reserved, since we have metadata right after the reserved context input + let _reserved: [u8; Self::SIZE_RESERVED] = bincode::Decode::decode(d)?; + Ok(Self { block: BlockContextV1 { chain_id: block_chain_id, @@ -293,15 +298,23 @@ impl bincode::Decode for SharedContextInputV1 { } impl SharedContextInputV1 { - pub const SIZE: usize = 1024; // size of encoded struct + pub const SIZE: usize = 1024; // total size of encoded struct + pub const SIZE_RESERVED: usize = 642; // size reserved for new fields + + pub fn decode_type_from_slice>( + buf: &[u8], + ) -> Result { + let (result, _) = bincode::decode_from_slice(buf, BINCODE_CONFIG_DEFAULT)?; + Ok(result) + } pub fn decode_from_slice(buf: &[u8]) -> Result { - let (result, _) = bincode::decode_from_slice(buf, bincode::config::legacy())?; + let result = Self::decode_type_from_slice(buf)?; Ok(result) } pub fn encode_to_vec(&self) -> Result { - let result: Bytes = bincode::encode_to_vec(self, bincode::config::legacy())?.into(); + let result: Bytes = bincode::encode_to_vec(self, BINCODE_CONFIG_DEFAULT)?.into(); Ok(result) } } @@ -314,11 +327,11 @@ mod tests { #[test] fn test_size_is_correct() { assert_eq!(SharedContextInputV1::SIZE, 1024); + assert_eq!(SharedContextInputV1::SIZE_RESERVED, 642); } - #[test] - fn test_serialize_context() { - let context = SharedContextInputV1 { + fn example_context() -> SharedContextInputV1 { + SharedContextInputV1 { block: BlockContextV1 { chain_id: 1, coinbase: Address::from(hex!("1000000000000000000000000000000000000001")), @@ -347,19 +360,24 @@ mod tests { value: U256::from(0), gas_limit: 100_000, }, - }; + } + } + + #[test] + fn test_simple_context_serialize() { + let context = example_context(); let encoded = context.encode_to_vec().unwrap(); + assert_eq!(encoded.len(), SharedContextInputV1::SIZE); let decoded = SharedContextInputV1::decode_from_slice(&encoded).unwrap(); assert_eq!(context, decoded); - assert_eq!(encoded.len(), SharedContextInputV1::SIZE); } #[test] fn test_serialize_default_context() { let context = SharedContextInputV1::default(); let encoded = context.encode_to_vec().unwrap(); + assert_eq!(encoded.len(), SharedContextInputV1::SIZE); let decoded = SharedContextInputV1::decode_from_slice(&encoded).unwrap(); assert_eq!(context, decoded); - assert_eq!(encoded.len(), SharedContextInputV1::SIZE); } } diff --git a/crates/sdk/src/types/sdk.rs b/crates/sdk/src/types/sdk.rs index e7b2d21d9..a8ad038b8 100644 --- a/crates/sdk/src/types/sdk.rs +++ b/crates/sdk/src/types/sdk.rs @@ -68,11 +68,16 @@ pub trait SharedAPI: StorageAPI + MetadataAPI + MetadataStorageAPI { fn charge_fuel(&self, fuel_consumed: u64); - fn sync_evm_gas(&self, gas_consumed: u64) { + fn sync_evm_gas(&self, gas_consumed: u64) -> Result<(), ExitCode> { let fuel_consumed = gas_consumed .checked_mul(FUEL_DENOM_RATE) .unwrap_or(u64::MAX); + let fuel_remaining = self.fuel(); + if fuel_consumed > fuel_remaining { + return Err(ExitCode::OutOfFuel); + } self.charge_fuel(fuel_consumed); + Ok(()) } fn fuel(&self) -> u64; diff --git a/crates/svm/src/builtins.rs b/crates/svm/src/builtins.rs index add63975f..9e82385e6 100644 --- a/crates/svm/src/builtins.rs +++ b/crates/svm/src/builtins.rs @@ -159,7 +159,7 @@ macro_rules! log_str_common { #[cfg(not(feature = "use-extended-debug-log"))] use fluentbase_sdk::debug_log as log_macro; #[cfg(feature = "use-extended-debug-log")] - use fluentbase_sdk::debug_log_ext as log_macro; + use fluentbase_sdk::debug_log as log_macro; log_macro!("svm_log: {}", $value); } } @@ -669,7 +669,6 @@ declare_builtin_function!( // let endianness: solana_poseidon::Endianness = endianness.try_into().map_err(|_| RuntimeError::InvalidConversion)?; // // if vals_len > 12 { -// debug_log_ext!("Poseidon hashing {} sequences is not supported", vals_len); // return Err(SyscallError::InvalidLength.into()); // } // diff --git a/crates/svm/src/token_2022/processor.rs b/crates/svm/src/token_2022/processor.rs index 442d78158..db0eb984e 100644 --- a/crates/svm/src/token_2022/processor.rs +++ b/crates/svm/src/token_2022/processor.rs @@ -18,7 +18,7 @@ use crate::{ use alloc::{vec, vec::Vec}; use core::{cell::RefCell, marker::PhantomData}; use fluentbase_sdk::{ - debug_log, debug_log_ext, Address, ContextReader, SharedAPI, PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, + debug_log, Address, ContextReader, SharedAPI, PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, }; use fluentbase_svm_common::common::evm_address_from_pubkey; use fluentbase_universal_token::events::{ diff --git a/crates/testing/src/host.rs b/crates/testing/src/host.rs index 874d05651..dda122b0f 100644 --- a/crates/testing/src/host.rs +++ b/crates/testing/src/host.rs @@ -1,9 +1,9 @@ use core::cell::RefCell; use fluentbase_runtime::RuntimeContextWrapper; use fluentbase_sdk::{ - bytes::Buf, calc_create_metadata_address, Address, Bytes, ContextReader, ContractContextV1, ExitCode, - IsAccountEmpty, IsAccountOwnable, IsColdAccess, MetadataAPI, MetadataStorageAPI, SharedAPI, - SharedContextInputV1, StorageAPI, SyscallResult, B256, FUEL_DENOM_RATE, U256, + bytes::Buf, calc_create_metadata_address, Address, Bytes, ContextReader, ContractContextV1, + ExitCode, IsAccountEmpty, IsAccountOwnable, IsColdAccess, MetadataAPI, MetadataStorageAPI, + SharedAPI, SharedContextInputV1, StorageAPI, SyscallResult, B256, FUEL_DENOM_RATE, U256, }; use hashbrown::HashMap; use std::{mem::take, rc::Rc}; diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index c4ae3f8bb..58605f4f4 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -11,7 +11,7 @@ keywords.workspace = true categories.workspace = true [dependencies] -serde = { workspace = true, optional = true } +serde = { workspace = true, default-features = false } byteorder = { workspace = true, default-features = false } rwasm = { workspace = true } alloy-primitives = { workspace = true } @@ -19,13 +19,15 @@ strum_macros = { workspace = true } revm-primitives = { workspace = true } revm-precompile = { workspace = true } hashbrown = { workspace = true } -bincode = { workspace = true } +bincode = { workspace = true, features = ["alloc", "serde", "derive"] } paste = { workspace = true } +fluentbase-codec = { workspace = true } +fluentbase-codec-derive = { workspace = true } [features] default = ["std"] serde = [ - "dep:serde", "alloy-primitives/serde", + "alloy-primitives/serde", ] std = [ "rwasm/std", diff --git a/crates/types/src/exit_code.rs b/crates/types/src/exit_code.rs index bd0882b86..1dac2de00 100644 --- a/crates/types/src/exit_code.rs +++ b/crates/types/src/exit_code.rs @@ -80,6 +80,8 @@ pub enum ExitCode { Panic = -1, /// An internal error (mapped from the errors below for nested EVM calls) Err = -2, + /// An interruption created by runtime (only for system contracts) + InterruptionCalled = -3, /* Fluentbase Runtime Error Codes */ /// Function can only be invoked as the root entry call @@ -98,9 +100,14 @@ pub enum ExitCode { PrecompileError = -1008, /// Passed bytecode into executor is not supported NotSupportedBytecode = -1009, + /// State changed inside immutable call (static=true) StateChangeDuringStaticCall = -1010, + /// Create contract size limit reached (limit depends on the application type) CreateContractSizeLimit = -1011, + /// There is a collision on the contract creation (same address is derived) CreateContractCollision = -1012, + /// Created contract starts with invalid bytes (`0xEF`). + CreateContractStartingWithEF = -1013, /* Trap Error Codes */ /// Execution reached a code path marked as unreachable @@ -193,6 +200,7 @@ impl From<&TrapCode> for ExitCode { TrapCode::BadSignature => ExitCode::BadSignature, TrapCode::OutOfFuel => ExitCode::OutOfFuel, TrapCode::UnknownExternalFunction => ExitCode::UnknownExternalFunction, + TrapCode::InterruptionCalled => ExitCode::InterruptionCalled, _ => ExitCode::UnknownError, } } diff --git a/crates/types/src/genesis.rs b/crates/types/src/genesis.rs index 07aa55c0d..333e8579f 100644 --- a/crates/types/src/genesis.rs +++ b/crates/types/src/genesis.rs @@ -22,6 +22,7 @@ pub const PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME: Address = address!("0x0000000000000000000000000000000000520008"); pub const PRECOMPILE_WASM_RUNTIME: Address = address!("0x0000000000000000000000000000000000520009"); pub const PRECOMPILE_EIP2935: Address = address!("0x0000F90827F1C53a10cb7A02335B175320002935"); +pub const PRECOMPILE_EIP7951: Address = address!("0x0000000000000000000000000000000000000100"); const fn evm_address(value: u8) -> Address { Address::with_last_byte(value) @@ -63,6 +64,10 @@ pub const PRECOMPILE_ADDRESSES: &[Address] = &[ PRECOMPILE_BN256_MUL, PRECOMPILE_BN256_PAIR, PRECOMPILE_EIP2935, + // TODO(dmitry123): Enabling this const here causes 2 evm e2e tests to fail (non-empty acc +2500 gas): + // 1. failed_tx_xcf416c53_paris + // 2. precompile_absence + // PRECOMPILE_EIP7951, PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, PRECOMPILE_EVM_RUNTIME, PRECOMPILE_FAIRBLOCK_VERIFIER, @@ -84,11 +89,45 @@ pub fn is_system_precompile(address: &Address) -> bool { PRECOMPILE_ADDRESSES.contains(address) } -pub fn is_execute_using_aot_compiler(address: &Address) -> bool { - // TODO(dmitry123): Add spec check here, once we have first fork +pub fn is_execute_using_wasmtime_strategy(address: &Address) -> bool { PRECOMPILE_ADDRESSES.contains(address) } +pub const EXECUTE_USING_SYSTEM_RUNTIME_ADDRESSES: &[Address] = &[ + PRECOMPILE_BIG_MODEXP, + PRECOMPILE_BLAKE2F, + PRECOMPILE_BLS12_381_G1_ADD, + PRECOMPILE_BLS12_381_G1_MSM, + PRECOMPILE_BLS12_381_G2_ADD, + PRECOMPILE_BLS12_381_G2_MSM, + PRECOMPILE_BLS12_381_MAP_G1, + PRECOMPILE_BLS12_381_MAP_G2, + PRECOMPILE_BLS12_381_PAIRING, + PRECOMPILE_BN256_ADD, + PRECOMPILE_BN256_MUL, + PRECOMPILE_BN256_PAIR, + // PRECOMPILE_EIP2935, + // PRECOMPILE_EIP7951, + // PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, + PRECOMPILE_EVM_RUNTIME, + // PRECOMPILE_FAIRBLOCK_VERIFIER, + PRECOMPILE_IDENTITY, + PRECOMPILE_KZG_POINT_EVALUATION, + // PRECOMPILE_NITRO_VERIFIER, + // PRECOMPILE_OAUTH2_VERIFIER, + PRECOMPILE_RIPEMD160, + PRECOMPILE_SECP256K1_RECOVER, + PRECOMPILE_SHA256, + // PRECOMPILE_SVM_RUNTIME, + // PRECOMPILE_WASM_RUNTIME, + // PRECOMPILE_WEBAUTHN_VERIFIER, + // PRECOMPILE_WRAPPED_ETH, +]; + +pub fn is_execute_using_system_runtime(address: &Address) -> bool { + EXECUTE_USING_SYSTEM_RUNTIME_ADDRESSES.contains(address) +} + /// Resolves and returns the account owner `Address` based on the provided input byte slice. /// /// # Parameters diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 4ad905c94..fa1e5fe1a 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -11,12 +11,14 @@ pub mod fd; mod genesis; mod import_linker; mod native_api; +mod runtime; #[cfg(target_arch = "wasm32")] mod rwasm_context; mod sys_func_idx; mod syscall; pub use alloy_primitives::*; +pub use bincode; pub use block_fuel::*; pub use bytecode::*; pub use byteorder; @@ -27,6 +29,7 @@ pub use genesis::*; pub use hashbrown::{self, hash_map, hash_set, HashMap, HashSet}; pub use import_linker::*; pub use native_api::*; +pub use runtime::*; #[cfg(target_arch = "wasm32")] pub use rwasm_context::{bindings, RwasmContext}; pub use sys_func_idx::*; diff --git a/crates/types/src/runtime.rs b/crates/types/src/runtime.rs new file mode 100644 index 000000000..24c8bb62d --- /dev/null +++ b/crates/types/src/runtime.rs @@ -0,0 +1,76 @@ +use crate::ExitCode; +use alloc::vec::Vec; +use alloy_primitives::Bytes; + +#[derive(Default, Clone, Debug, PartialEq)] +pub struct RuntimeNewFrameInputV1 { + pub metadata: Bytes, + pub input: Bytes, +} + +impl bincode::Encode for RuntimeNewFrameInputV1 { + fn encode( + &self, + e: &mut E, + ) -> Result<(), bincode::error::EncodeError> { + bincode::Encode::encode(self.metadata.as_ref(), e)?; + bincode::Encode::encode(&self.input.as_ref(), e)?; + Ok(()) + } +} + +impl bincode::Decode for RuntimeNewFrameInputV1 { + fn decode>( + d: &mut D, + ) -> Result { + let metadata: Vec = bincode::Decode::decode(d)?; + let input: Vec = bincode::Decode::decode(d)?; + Ok(Self { + metadata: metadata.into(), + input: input.into(), + }) + } +} + +#[derive(Default, Clone, Debug, PartialEq)] +pub struct RuntimeInterruptionOutcomeV1 { + pub halted_frame: bool, + pub output: Bytes, + pub fuel_consumed: u64, + pub fuel_refunded: i64, + pub exit_code: ExitCode, +} + +impl bincode::Encode for RuntimeInterruptionOutcomeV1 { + fn encode( + &self, + e: &mut E, + ) -> Result<(), bincode::error::EncodeError> { + bincode::Encode::encode(&self.halted_frame, e)?; + bincode::Encode::encode(self.output.as_ref(), e)?; + bincode::Encode::encode(&self.fuel_consumed, e)?; + bincode::Encode::encode(&self.fuel_refunded, e)?; + let exit_code = self.exit_code.into_i32(); + bincode::Encode::encode(&exit_code, e)?; + Ok(()) + } +} + +impl bincode::Decode for RuntimeInterruptionOutcomeV1 { + fn decode>( + d: &mut D, + ) -> Result { + let halted_frame: bool = bincode::Decode::decode(d)?; + let output: Vec = bincode::Decode::decode(d)?; + let fuel_consumed: u64 = bincode::Decode::decode(d)?; + let fuel_refunded: i64 = bincode::Decode::decode(d)?; + let exit_code: i32 = bincode::Decode::decode(d)?; + Ok(Self { + halted_frame, + output: output.into(), + fuel_consumed, + fuel_refunded, + exit_code: ExitCode::from(exit_code), + }) + } +} diff --git a/crates/types/src/syscall.rs b/crates/types/src/syscall.rs index 36cdade50..b7fa9a670 100644 --- a/crates/types/src/syscall.rs +++ b/crates/types/src/syscall.rs @@ -1,11 +1,12 @@ -use crate::{Bytes, ExitCode, B256}; +use crate::{ExitCode, B256}; use alloc::{string::String, vec::Vec}; +use core::ops::Range; #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SyscallInvocationParams { pub code_hash: B256, - pub input: Bytes, + pub input: Range, pub fuel_limit: u64, pub state: u32, pub fuel16_ptr: u32, @@ -18,7 +19,7 @@ impl SyscallInvocationParams { pub fn decode(bytes: &[u8]) -> Option { let (result, _bytes_read) = - bincode::decode_from_slice(bytes, bincode::config::legacy()).unwrap(); + bincode::decode_from_slice(bytes, bincode::config::legacy()).ok()?; Some(result) } } @@ -32,7 +33,7 @@ impl ::bincode::Encode for SyscallInvocationParams { ::bincode::Encode::encode(&self.fuel_limit, encoder)?; ::bincode::Encode::encode(&self.state, encoder)?; ::bincode::Encode::encode(&self.fuel16_ptr, encoder)?; - ::bincode::Encode::encode(&self.input[..], encoder)?; + ::bincode::Encode::encode(&self.input, encoder)?; Ok(()) } } @@ -41,12 +42,11 @@ impl<__Context> ::bincode::Decode<__Context> for SyscallInvocationParams { fn decode<__D: ::bincode::de::Decoder>( decoder: &mut __D, ) -> Result { - use alloc::vec::Vec; let code_hash: [u8; 32] = bincode::Decode::decode(decoder)?; let fuel_limit: u64 = bincode::Decode::decode(decoder)?; let state: u32 = bincode::Decode::decode(decoder)?; let fuel16_ptr: u32 = bincode::Decode::decode(decoder)?; - let input: Vec = bincode::Decode::decode(decoder)?; + let input: Range = bincode::Decode::decode(decoder)?; Ok(Self { code_hash: B256::from(code_hash), input: input.into(), diff --git a/e2e/Cargo.toml b/e2e/Cargo.toml index dfa7ae1bb..61c8308ae 100644 --- a/e2e/Cargo.toml +++ b/e2e/Cargo.toml @@ -41,7 +41,7 @@ solana-curve25519 = { workspace = true, default-features = false } solana-bn254 = { workspace = true, default-features = false } solana-poseidon = { workspace = true, default-features = false } solana-program-pack = { workspace = true, default-features = false } -solana-program-option = { workspace = true, default-features = false } +#solana-program-option = { workspace = true, default-features = false } serde = { workspace = true } serde_json = { workspace = true } array-bytes = { workspace = true } diff --git a/e2e/benches/erc20.rs b/e2e/benches/erc20.rs index e81c8eb59..33027b702 100644 --- a/e2e/benches/erc20.rs +++ b/e2e/benches/erc20.rs @@ -1,5 +1,6 @@ use criterion::{criterion_main, Criterion}; use fluentbase_e2e::EvmTestingContextWithGenesis; +use fluentbase_runtime::default_runtime_executor; use fluentbase_sdk::{ address, constructor::encode_constructor_params, Address, Bytes, ContractContextV1, PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, UNIVERSAL_TOKEN_MAGIC_BYTES, @@ -114,127 +115,127 @@ fn erc20_transfer_benches(c: &mut Criterion) { } // --- Benchmark 4: Precompiled Universal Token --- - { - let mut ctx = EvmTestingContext::default().with_full_genesis(); - const USER_ADDRESS1: Address = address!("1111111111111111111111111111111111111111"); - const USER_ADDRESS2: Address = address!("2222222222222222222222222222222222222222"); - const USER_ADDRESS5: Address = address!("5555555555555555555555555555555555555555"); - const USER_ADDRESS6: Address = address!("6666666666666666666666666666666666666666"); - ctx.sdk = ctx.sdk.with_contract_context(ContractContextV1 { - address: PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, - ..Default::default() - }); - ctx.sdk - .set_ownable_account_address(PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME); - - pub fn build_input(prefix: &[u8], instruction: &Instruction) -> Result, SvmError> { - let mut input: Vec = prefix.to_vec(); - serialize_svm_program_params_from_instruction(&mut input, instruction) - .expect("failed to serialize program params into init_bytecode"); - Ok(input) - } - - pub fn call_with_sig( - ctx: &mut EvmTestingContext, - input: Bytes, - caller: &Address, - callee: &Address, - ) -> Result, u32> { - let result = ctx.call_evm_tx(*caller, *callee, input, None, None); - match &result { - ExecutionResult::Revert { - gas_used: _, - output, - } => { - let output_vec = output.to_vec(); - try_print_utf8_error(&output_vec); - let error_code = u32::from_be_bytes(output_vec[32..].try_into().unwrap()); - Err(error_code) - } - ExecutionResult::Success { output, .. } => Ok(output.data().to_vec()), - _ => { - panic!("expected revert, got: {:?}", &result) - } - } - } - - let program_id = token_2022::lib::id(); - let account1_key = pubkey_from_evm_address::(&USER_ADDRESS1); - let account2_key = pubkey_from_evm_address::(&USER_ADDRESS2); - let owner_key = pubkey_from_evm_address::(&USER_ADDRESS5); - let mint_key = pubkey_from_evm_address::(&USER_ADDRESS6); - - let initialize_mint_instruction = - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(); - - let init_bytecode = build_input(&UNIVERSAL_TOKEN_MAGIC_BYTES, &initialize_mint_instruction) - .expect("failed to build input"); - let contract_address = ctx.deploy_evm_tx(USER_ADDRESS5, init_bytecode.clone().into()); - - ctx.commit_db_to_sdk(); - - let initialize_account1_instruction = - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(); - let input = build_input( - &sig_to_bytes(SIG_TOKEN2022), - &initialize_account1_instruction, - ) - .expect("failed to build input"); - let _output_data = - call_with_sig(&mut ctx, input.into(), &USER_ADDRESS1, &contract_address).unwrap(); - - let initialize_account2_instruction = - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(); - let input = build_input( - &sig_to_bytes(SIG_TOKEN2022), - &initialize_account2_instruction, - ) - .expect("failed to build input"); - let _output_data = - call_with_sig(&mut ctx, input.into(), &USER_ADDRESS2, &contract_address).unwrap(); - - // mint to account - let mint_to_instruction = mint_to( - &program_id, - &mint_key, - &account1_key, - &owner_key, - &[], - u64::MAX, - ) - .unwrap(); - let input = build_input(&sig_to_bytes(SIG_TOKEN2022), &mint_to_instruction) - .expect("failed to build input"); - let _output_data = - call_with_sig(&mut ctx, input.into(), &USER_ADDRESS5, &contract_address).unwrap(); - - // source-owner transfer - #[allow(deprecated)] - let transfer_instruction = token_2022::instruction::transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 1, - ) - .unwrap(); - let input = build_input(&sig_to_bytes(SIG_TOKEN2022), &transfer_instruction) - .expect("failed to build input"); - - group.bench_function("4_Precompiled_UniversalToken", |b| { - // Note: Manual warmup calls are not needed. Criterion handles warmups automatically. - b.iter(|| { - let _result = ctx.call_evm_tx( - USER_ADDRESS1, - contract_address, - input.clone().into(), - None, - None, - ); - }); - }); - } + // { + // let mut ctx = EvmTestingContext::default().with_full_genesis(); + // const USER_ADDRESS1: Address = address!("1111111111111111111111111111111111111111"); + // const USER_ADDRESS2: Address = address!("2222222222222222222222222222222222222222"); + // const USER_ADDRESS5: Address = address!("5555555555555555555555555555555555555555"); + // const USER_ADDRESS6: Address = address!("6666666666666666666666666666666666666666"); + // ctx.sdk = ctx.sdk.with_contract_context(ContractContextV1 { + // address: PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME, + // ..Default::default() + // }); + // ctx.sdk + // .set_ownable_account_address(PRECOMPILE_UNIVERSAL_TOKEN_RUNTIME); + // + // pub fn build_input(prefix: &[u8], instruction: &Instruction) -> Result, SvmError> { + // let mut input: Vec = prefix.to_vec(); + // serialize_svm_program_params_from_instruction(&mut input, instruction) + // .expect("failed to serialize program params into init_bytecode"); + // Ok(input) + // } + // + // pub fn call_with_sig( + // ctx: &mut EvmTestingContext, + // input: Bytes, + // caller: &Address, + // callee: &Address, + // ) -> Result, u32> { + // let result = ctx.call_evm_tx(*caller, *callee, input, None, None); + // match &result { + // ExecutionResult::Revert { + // gas_used: _, + // output, + // } => { + // let output_vec = output.to_vec(); + // try_print_utf8_error(&output_vec); + // let error_code = u32::from_be_bytes(output_vec[32..].try_into().unwrap()); + // Err(error_code) + // } + // ExecutionResult::Success { output, .. } => Ok(output.data().to_vec()), + // _ => { + // panic!("expected revert, got: {:?}", &result) + // } + // } + // } + // + // let program_id = token_2022::lib::id(); + // let account1_key = pubkey_from_evm_address::(&USER_ADDRESS1); + // let account2_key = pubkey_from_evm_address::(&USER_ADDRESS2); + // let owner_key = pubkey_from_evm_address::(&USER_ADDRESS5); + // let mint_key = pubkey_from_evm_address::(&USER_ADDRESS6); + // + // let initialize_mint_instruction = + // initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(); + // + // let init_bytecode = build_input(&UNIVERSAL_TOKEN_MAGIC_BYTES, &initialize_mint_instruction) + // .expect("failed to build input"); + // let contract_address = ctx.deploy_evm_tx(USER_ADDRESS5, init_bytecode.clone().into()); + // + // ctx.commit_db_to_sdk(); + // + // let initialize_account1_instruction = + // initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(); + // let input = build_input( + // &sig_to_bytes(SIG_TOKEN2022), + // &initialize_account1_instruction, + // ) + // .expect("failed to build input"); + // let _output_data = + // call_with_sig(&mut ctx, input.into(), &USER_ADDRESS1, &contract_address).unwrap(); + // + // let initialize_account2_instruction = + // initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(); + // let input = build_input( + // &sig_to_bytes(SIG_TOKEN2022), + // &initialize_account2_instruction, + // ) + // .expect("failed to build input"); + // let _output_data = + // call_with_sig(&mut ctx, input.into(), &USER_ADDRESS2, &contract_address).unwrap(); + // + // // mint to account + // let mint_to_instruction = mint_to( + // &program_id, + // &mint_key, + // &account1_key, + // &owner_key, + // &[], + // u64::MAX, + // ) + // .unwrap(); + // let input = build_input(&sig_to_bytes(SIG_TOKEN2022), &mint_to_instruction) + // .expect("failed to build input"); + // let _output_data = + // call_with_sig(&mut ctx, input.into(), &USER_ADDRESS5, &contract_address).unwrap(); + // + // // source-owner transfer + // #[allow(deprecated)] + // let transfer_instruction = token_2022::instruction::transfer( + // &program_id, + // &account1_key, + // &account2_key, + // &account1_key, + // &[], + // 1, + // ) + // .unwrap(); + // let input = build_input(&sig_to_bytes(SIG_TOKEN2022), &transfer_instruction) + // .expect("failed to build input"); + // + // group.bench_function("4_Precompiled_UniversalToken", |b| { + // // Note: Manual warmup calls are not needed. Criterion handles warmups automatically. + // b.iter(|| { + // let _result = ctx.call_evm_tx( + // USER_ADDRESS1, + // contract_address, + // input.clone().into(), + // None, + // None, + // ); + // }); + // }); + // } group.finish(); } diff --git a/e2e/src/bench.rs b/e2e/src/bench.rs new file mode 100644 index 000000000..649633127 --- /dev/null +++ b/e2e/src/bench.rs @@ -0,0 +1,41 @@ +use crate::EvmTestingContextWithGenesis; +use fluentbase_sdk::{constructor::encode_constructor_params, hex, Address, Bytes}; +use fluentbase_testing::EvmTestingContext; + +#[test] +fn test_bench_erc20_transfer() { + let mut ctx = EvmTestingContext::default().with_full_genesis(); + const OWNER_ADDRESS: Address = Address::ZERO; + let bytecode: &[u8] = fluentbase_contracts::FLUENTBASE_EXAMPLES_ERC20 + .wasm_bytecode + .into(); + + // constructor params for ERC20: + // name: "TestToken" + // symbol: "TST" + // initial_supply: 1_000_000 + // use examples/erc20/src/lib.rs print_constructor_params_hex() to regenerate + let constructor_params = hex!("000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000000000954657374546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035453540000000000000000000000000000000000000000000000000000000000"); + + let encoded_constructor_params = encode_constructor_params(&constructor_params); + let mut input: Vec = Vec::new(); + input.extend(bytecode); + input.extend(encoded_constructor_params); + + let contract_address = ctx.deploy_evm_tx(OWNER_ADDRESS, input.into()); + let transfer_payload: Bytes = hex!("a9059cbb00000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001").into(); + + for _ in 0..1_000 { + let result = ctx.call_evm_tx( + OWNER_ADDRESS, + contract_address, + transfer_payload.clone(), + None, + None, + ); + if !result.is_success() { + println!("{:?}", result); + } + assert!(result.is_success()) + } +} diff --git a/e2e/src/ddos.rs b/e2e/src/ddos.rs new file mode 100644 index 000000000..e595f18e6 --- /dev/null +++ b/e2e/src/ddos.rs @@ -0,0 +1,96 @@ +use crate::EvmTestingContextWithGenesis; +use fluentbase_sdk::{calc_create_address, Address, Bytes}; +use fluentbase_testing::{EvmTestingContext, TxBuilder}; +use wat::parse_str; + +const EXEC_BALANCE_DOS_WAT: &str = r#" + (module + (import "fluentbase_v1preview" "_read" (func $_read (param i32 i32 i32))) + (import "fluentbase_v1preview" "_exec" (func $_exec (param i32 i32 i32 i32 i32) (result i32))) + (import "fluentbase_v1preview" "_exit" (func $_exit (param i32))) + (memory 1) + (data (i32.const 64) + "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0b") + (func $main (local $len i32) + ;; Read the caller-supplied length into memory[0..4]. + ;; + ;; Note that the first 1024 bytes are encoded context from the system, so we need to load from byte 1024 + ;; https://github.com/fluentlabs-xyz/fluentbase/blob/e88ea5712c2eb568a6cd9c8946db48064de41ab0/crates/revm/src/executor.rs#L154-L158 + i32.const 0 ;; target ptr + i32.const 1024 ;; offset + i32.const 4 ;; length + call $_read + + i32.const 0 + i32.load + local.set $len + + ;; Provision a large memory buffer up-front so both test cases have identical growth costs. + i32.const 512 + memory.grow + drop + + ;; Invoke the BALANCE syscall via _exec with an attacker-controlled input length. + i32.const 64 ;; pointer to SYSCALL_ID_BALANCE + i32.const 128 ;; input pointer + local.get $len ;; attacker-chosen length + i32.const 0 ;; no explicit fuel limit + i32.const 0 ;; STATE_MAIN + call $_exec + drop + + ;; Exit without bubbling up the nested error. + i32.const 0 + call $_exit + ) + (export "main" (func $main)) + (export "memory" (memory 0)) + ) +"#; + +fn deploy_exec_balance_contract(ctx: &mut EvmTestingContext) -> Address { + let wasm = parse_str(EXEC_BALANCE_DOS_WAT).expect("invalid wat"); + let deployer = Address::ZERO; + let deploy_result = TxBuilder::create(ctx, deployer, wasm.into()) + .gas_price(0) + .gas_limit(50_000_000) + .exec(); + assert!( + deploy_result.is_success(), + "failed to deploy exec test contract: {deploy_result:?}" + ); + calc_create_address(&deployer, 0) +} + +fn call_with_len( + ctx: &mut EvmTestingContext, + contract: Address, + len: u32, +) -> revm::context::result::ExecutionResult { + let calldata = Bytes::from(len.to_le_bytes().to_vec()); + TxBuilder::call(ctx, Address::ZERO, contract, None) + .gas_price(0) + .gas_limit(22_000) + .input(calldata) + .exec() +} + +#[test] +fn ddos_balance_rejects_huge_input_without_memory_copy() { + let mut ctx = EvmTestingContext::default().with_full_genesis(); + let contract = deploy_exec_balance_contract(&mut ctx); + + // Ensure gas cost is independent of input length. + const SMALL_LEN: u32 = 20; + // 32MB of unmetered input copying + const LARGE_LEN: u32 = 20 * 1024 * 1024; + + let small = call_with_len(&mut ctx, contract, SMALL_LEN); + assert!( + small.is_success(), + "baseline call unexpectedly failed: {small:?}" + ); + + let large = call_with_len(&mut ctx, contract, LARGE_LEN); + assert!(large.is_halt(), "large call should halt: {large:?}"); +} diff --git a/e2e/src/evm.rs b/e2e/src/evm.rs index e82a0bc29..2e7c9ef5a 100644 --- a/e2e/src/evm.rs +++ b/e2e/src/evm.rs @@ -200,10 +200,7 @@ fn test_evm_self_destruct() { .gas_price(gas_price) .exec(); if !result.is_success() { - println!( - "{}", - from_utf8(result.output().cloned().unwrap_or_default().as_ref()).unwrap_or("") - ); + try_print_utf8_error(result.output().cloned().unwrap_or_default().as_ref()); } assert!(result.is_success()); assert_eq!(result.gas_used(), 51003); @@ -282,7 +279,7 @@ fn test_evm_erc20() { #[test] fn test_evm_balance() { - const OWNER_ADDRESS: Address = address!("1111111111111111111111111111111111111111"); + const OWNER_ADDRESS: Address = Address::repeat_byte(0x11); let mut bytecode = Vec::new(); bytecode.push(opcode::PUSH20); bytecode.extend_from_slice(OWNER_ADDRESS.as_slice()); @@ -301,15 +298,16 @@ fn test_evm_balance() { ); let result = ctx.call_evm_tx(OWNER_ADDRESS, contract_address, hex!("").into(), None, None); println!("{:?}", result); + if !result.is_success() { + try_print_utf8_error(result.output().cloned().unwrap_or_default().as_ref()); + } assert!(result.is_success()); let output = result.into_output().unwrap_or_default(); assert_eq!(output.len(), 32); // assert_eq!(result.gas_used(), 21116); let balance = U256::from_be_slice(output.as_ref()); - assert_eq!( - balance, - U256::from_str_radix("999999999997000000", 10).unwrap() - ); + let expected_balance = U256::from_str_radix("999999999997000000", 10).unwrap(); + assert_eq!(balance, expected_balance); } #[test] diff --git a/e2e/src/lib.rs b/e2e/src/lib.rs index 092e5c21a..118179128 100644 --- a/e2e/src/lib.rs +++ b/e2e/src/lib.rs @@ -43,11 +43,18 @@ pub mod svm; // Testnet-only: Runtime upgrade functionality. See frame_init() for details. #[cfg(feature = "fluent-testnet")] #[cfg(test)] -mod update_account; +mod ddos; +// #[cfg(test)] +// mod erc20; #[cfg(test)] -mod wasm; +mod bench; #[cfg(test)] mod exec_input; +#[cfg(feature = "fluent-testnet")] +#[cfg(test)] +mod update_account; +#[cfg(test)] +mod wasm; pub trait EvmTestingContextWithGenesis { fn with_full_genesis(self) -> Self; diff --git a/e2e/src/update_account.rs b/e2e/src/update_account.rs index 71e77dbea..95eb1a11d 100644 --- a/e2e/src/update_account.rs +++ b/e2e/src/update_account.rs @@ -45,6 +45,9 @@ fn test_update_account_code_by_auth_v1() { (func (export "main") unreachable ) + (func (export "deploy") + unreachable + ) ) "#, ) @@ -75,6 +78,7 @@ fn test_update_account_code_by_auth_v1() { None, None, ); + println!("result: {:?}", result); assert!(result.is_halt()); } @@ -115,6 +119,9 @@ fn test_update_account_code_by_auth_v2() { (func (export "main") unreachable ) + (func (export "deploy") + unreachable + ) ) "#, ) diff --git a/evm-e2e/Cargo.lock b/evm-e2e/Cargo.lock index 6b682c30f..f088fb4c3 100644 --- a/evm-e2e/Cargo.lock +++ b/evm-e2e/Cargo.lock @@ -18,7 +18,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.37" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7f1c9a1ccc7f3e03c36976455751a6166a4f0d2d2c530c3f87dfe7d0cdc836" +checksum = "07d9a64522a0db6ebcc4ff9c904e329e77dd737c2c25d30f1bdc32ca6c6ce334" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.0.37" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1421f6c9d15e5b86afbfe5865ca84dea3b9f77173a0963c1a2ee4e626320ada9" +checksum = "675b163946b343ed2ddde4416114ad61fabc8b2a50d08423f38aa0ac2319e800" dependencies = [ "alloy-eips", "alloy-primitives", @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2acb6637a9c0e1cdf8971e0ced8f3fa34c04c5e9dccf6bb184f6a64fe0e37d8" +checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b77f7d5e60ad8ae6bd2200b8097919712a07a6db622a4b201e7ead6166f02e5" +checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", @@ -128,7 +128,7 @@ dependencies = [ "derive_more 2.0.1", "foldhash 0.2.0", "hashbrown 0.16.0", - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "k256", "keccak-asm", @@ -161,14 +161,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "alloy-serde" -version = "1.0.37" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5413814be7a22fbc81e0f04a2401fcc3eb25e56fd53b04683e8acecc6e1fe01b" +checksum = "596cfa360922ba9af901cc7370c68640e4f72adb6df0ab064de32f21fec498d7" dependencies = [ "alloy-primitives", "serde", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5772107f9bb265d8d8c86e0733937bb20d0857ea5425b1b6ddf51a9804042" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "alloy-json-abi", "const-hex", @@ -189,15 +189,15 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e188b939aa4793edfaaa099cb1be4e620036a775b4bdf24fdc56f1cd6fd45890" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", "winnow", @@ -243,6 +243,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object 0.32.2", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -379,7 +388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -417,7 +426,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -506,7 +515,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -565,7 +574,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -597,7 +606,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -704,11 +713,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -753,7 +762,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -762,7 +771,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -828,7 +837,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -895,9 +904,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.39" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "jobserver", @@ -968,7 +977,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -994,9 +1003,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6407bff74dea37e0fa3dc1c1c974e5d46405f0c987bf9997a0762adce71eda6" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", "cpufeatures", @@ -1012,9 +1021,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -1276,7 +1285,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", "rand_core 0.6.4", "subtle", "zeroize", @@ -1288,7 +1297,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", "typenum", ] @@ -1354,7 +1363,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1388,7 +1397,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1402,7 +1411,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1413,7 +1422,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1424,7 +1433,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1527,9 +1536,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1554,7 +1563,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1583,7 +1592,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1594,7 +1603,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "unicode-xid", ] @@ -1604,7 +1613,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.9", ] [[package]] @@ -1647,7 +1656,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1669,9 +1678,9 @@ checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" [[package]] name = "dtor" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" +checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" dependencies = [ "dtor-proc-macro", ] @@ -1717,7 +1726,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1739,7 +1748,7 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array 0.14.7", + "generic-array 0.14.9", "group", "hkdf", "pem-rfc7468", @@ -1779,22 +1788,22 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1810,7 +1819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1898,9 +1907,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "five8_const" @@ -1937,7 +1946,7 @@ dependencies = [ "byteorder", "bytes", "fluentbase-codec-derive", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", ] @@ -1950,7 +1959,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1991,6 +2000,7 @@ dependencies = [ "revm-rwasm-context", "revm-rwasm-interpreter", "revm-rwasm-primitives", + "serde", ] [[package]] @@ -2053,8 +2063,9 @@ dependencies = [ "fluentbase-crypto", "fluentbase-sdk-derive", "fluentbase-types", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "rwasm", + "spin 0.10.0", ] [[package]] @@ -2067,7 +2078,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2086,7 +2097,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", "thiserror 2.0.17", "tracing", @@ -2098,7 +2109,7 @@ version = "0.4.11-dev" dependencies = [ "arrayref", "bincode 2.0.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "blake3", "bytemuck", "bytemuck_derive", @@ -2106,7 +2117,7 @@ dependencies = [ "fluentbase-sdk", "fluentbase-svm-common", "fluentbase-universal-token", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "itertools 0.14.0", "lazy_static", "num-derive", @@ -2162,11 +2173,14 @@ dependencies = [ "alloy-primitives", "bincode 2.0.1", "byteorder", - "hashbrown 0.15.5", + "fluentbase-codec", + "fluentbase-codec-derive", + "hashbrown 0.16.0", "paste", "revm-rwasm-precompile", "revm-rwasm-primitives", "rwasm", + "serde", "strum_macros 0.27.2", ] @@ -2260,7 +2274,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2308,7 +2322,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "debugid", "fxhash", "serde", @@ -2323,9 +2337,9 @@ checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2368,14 +2382,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] [[package]] @@ -2385,7 +2399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", - "indexmap 2.11.4", + "indexmap 2.12.0", "stable_deref_trait", ] @@ -2587,7 +2601,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.1", + "windows-core 0.62.2", ] [[package]] @@ -2628,7 +2642,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2644,9 +2658,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -2669,7 +2683,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "web-time", ] @@ -2741,15 +2755,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -2815,9 +2829,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" @@ -2831,7 +2845,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", ] @@ -2946,11 +2960,10 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -2977,7 +2990,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3094,7 +3107,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3165,9 +3178,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -3175,14 +3188,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3205,6 +3218,15 @@ dependencies = [ "smallvec", ] +[[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" @@ -3213,7 +3235,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "memchr", ] @@ -3491,14 +3513,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -3506,15 +3528,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -3534,12 +3556,11 @@ dependencies = [ [[package]] name = "pest" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.17", "ucd-trie", ] @@ -3574,7 +3595,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3698,7 +3719,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit 0.23.7", ] [[package]] @@ -3727,23 +3748,22 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.4", - "lazy_static", + "bitflags 2.10.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -3756,10 +3776,11 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.26" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" dependencies = [ + "ar_archive_writer", "cc", ] @@ -3783,7 +3804,7 @@ checksum = "9276d404009cc49f3b8befeb8ffc1d868c5ea732bd9d72ab3e64231187f908c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3902,7 +3923,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "serde", ] @@ -3955,11 +3976,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -4001,7 +4022,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4020,9 +4041,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "revm-rwasm" @@ -4209,7 +4230,7 @@ version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2000ab9530cec61fce184fcea6362dfe69395fad0a46c79e0cfb686bd29111a4" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "revm-rwasm-bytecode", "revm-rwasm-primitives", "serde", @@ -4338,11 +4359,11 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4353,9 +4374,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -4426,7 +4447,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4443,9 +4464,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce" dependencies = [ "dyn-clone", "ref-cast", @@ -4487,7 +4508,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4498,7 +4519,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array 0.14.9", "pkcs8", "subtle", "zeroize", @@ -4589,7 +4610,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4598,7 +4619,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "memchr", "ryu", @@ -4617,19 +4638,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.0.5", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -4637,14 +4657,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4947,7 +4967,7 @@ source = "git+https://github.com/fluentlabs-xyz/agave?branch=feat%2Fsvm#ca0b8c4a dependencies = [ "base64 0.22.1", "bincode 2.0.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "blake3", "bs58", "bv", @@ -5106,7 +5126,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5225,9 +5245,9 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69234f4667ae1a00f7bfb90b42d6aa141744114b128ac262b9a28e9c869cf514" +checksum = "3e29cb79716167e58c0719d572e686880172f1816cd85e0acab74ea0ff3c795e" dependencies = [ "cfg-if", "dashu", @@ -5247,9 +5267,9 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a736bce661752b1d6ecf33eca197443fb535124b3caabd332862d6f8258e3c8d" +checksum = "7ac59616976c008e862f99d26fd0c1c037d464df33d9ca548be88f938f0b1bcf" dependencies = [ "quote", "syn 1.0.109", @@ -5257,9 +5277,9 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dddd8d022840c1c500e0d7f82e9b9cf080b7dabd469f06b394010e6a594f692b" +checksum = "0244dee3a7a0f88cf71c3edf518f4fc97794ae870a107cbe7c810ac3fbf879cb" dependencies = [ "bincode 1.3.3", "blake3", @@ -5277,9 +5297,9 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "5.2.1" +version = "5.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48b9b57606ab0eb9560f0456dc978166ab0a3bd9d8b3f2ab24ea5e1377c56f07" +checksum = "1f0cdde80366245a374d29fecdde2881286002a6e3f51b84f54b86560ed026e5" dependencies = [ "arrayref", "hashbrown 0.14.5", @@ -5305,7 +5325,6 @@ dependencies = [ "sp1-derive", "sp1-primitives", "strum", - "strum_macros 0.26.4", "sysinfo", "tracing", ] @@ -5340,9 +5359,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -5400,6 +5419,9 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] [[package]] name = "strum_macros" @@ -5411,7 +5433,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5423,7 +5445,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5445,9 +5467,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -5456,14 +5478,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2375c17f6067adc651d8c2c51658019cef32edfff4a982adaf1d7fd1c039f08b" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5500,10 +5522,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5550,7 +5572,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5561,7 +5583,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5651,9 +5673,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] @@ -5664,7 +5686,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -5674,21 +5696,21 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.7.2", + "indexmap 2.12.0", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -5718,7 +5740,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5748,7 +5770,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5805,9 +5827,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -5823,9 +5845,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -5919,15 +5941,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -5939,9 +5952,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -5950,25 +5963,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5976,22 +5975,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -6008,12 +6007,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" +checksum = "06d642d8c5ecc083aafe9ceb32809276a304547a3a6eeecceb5d8152598bc71f" dependencies = [ "leb128fmt", - "wasmparser 0.239.0", + "wasmparser 0.240.0", ] [[package]] @@ -6062,7 +6061,7 @@ version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -6071,21 +6070,21 @@ version = "0.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "semver 1.0.27", "serde", ] [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ - "bitflags 2.9.4", - "indexmap 2.11.4", + "bitflags 2.10.0", + "indexmap 2.12.0", "semver 1.0.27", ] @@ -6147,7 +6146,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -6175,7 +6174,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "smallvec", "target-lexicon", "thiserror 2.0.17", @@ -6196,9 +6195,9 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", - "object", + "object 0.36.7", "postcard", "rustc-demangle", "semver 1.0.27", @@ -6235,7 +6234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d83fa2dea686f76b5437b66045aae6351d359ee11cc4124f9842de63837b81" dependencies = [ "cc", - "object", + "object 0.36.7", "rustix", "wasmtime-versioned-export-macros", ] @@ -6270,7 +6269,7 @@ dependencies = [ "addr2line", "anyhow", "async-trait", - "bitflags 2.9.4", + "bitflags 2.10.0", "bumpalo", "cc", "cfg-if", @@ -6278,13 +6277,13 @@ dependencies = [ "fxprof-processed-profile", "gimli", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "ittapi", "libc", "log", "mach2", "memfd", - "object", + "object 0.36.7", "once_cell", "postcard", "psm", @@ -6333,7 +6332,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "pulley-interpreter", "smallvec", "target-lexicon", @@ -6358,7 +6357,7 @@ checksum = "4e052e1d9c30b8f31aff64380caaaff492a9890a412658bcc8866fe626b8e91f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6370,7 +6369,7 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object", + "object 0.36.7", "target-lexicon", "wasmparser 0.233.0", "wasmtime-cranelift", @@ -6386,37 +6385,37 @@ checksum = "f967f5efaaac7694e6bd0d67542a5a036830860e4adf95684260181e85a5d299" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.4", + "indexmap 2.12.0", "wit-parser", ] [[package]] name = "wast" -version = "239.0.0" +version = "240.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" +checksum = "b0efe1c93db4ac562b9733e3dca19ed7fc878dba29aef22245acf84f13da4a19" dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width 0.2.1", - "wasm-encoder 0.239.0", + "unicode-width 0.2.2", + "wasm-encoder 0.240.0", ] [[package]] name = "wat" -version = "1.239.0" +version = "1.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" +checksum = "4ec9b6eab7ecd4d639d78515e9ea491c9bacf494aa5eda10823bd35992cf8c1e" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -6463,7 +6462,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6513,9 +6512,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -6526,46 +6525,46 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -6585,7 +6584,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -6606,19 +6614,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 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", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -6629,9 +6637,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -6641,9 +6649,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -6653,9 +6661,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -6665,9 +6673,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -6677,9 +6685,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -6689,9 +6697,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -6701,9 +6709,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -6713,9 +6721,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -6740,7 +6748,7 @@ checksum = "f22f1cd55247a2e616870b619766e9522df36b7abafbb29bbeb34b7a9da7e9f0" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", "semver 1.0.27", "serde", @@ -6776,7 +6784,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6796,7 +6804,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] diff --git a/evm-e2e/Cargo.toml b/evm-e2e/Cargo.toml index 3204ce08d..4cc39378b 100644 --- a/evm-e2e/Cargo.toml +++ b/evm-e2e/Cargo.toml @@ -52,6 +52,8 @@ std = [ debug-print = [ "revm/debug-print", "fluentbase-revm/debug-print", + "fluentbase-sdk/debug-print", + "fluentbase-runtime/debug-print", # "rwasm/debug-print", ] wasmtime = [ diff --git a/evm-e2e/gen_tests.js b/evm-e2e/gen_tests.js index dcc0a534f..44bc90b41 100644 --- a/evm-e2e/gen_tests.js +++ b/evm-e2e/gen_tests.js @@ -117,8 +117,11 @@ const disabledTests = new Set([ 'static_loop_calls_depth_then_revert2', 'static_loop_calls_depth_then_revert3', 'static_return50000_2', - // failing tests (uncomment once fixed) - 'high_gas_price_paris', + 'contract_creation_spam', + 'static_call50000_identity', + 'static_call1_mb1024_calldepth', + 'static_loop_calls_then_revert', + 'static_call50000_rip160', ]); // Group tests by subdirectory (module name) diff --git a/evm-e2e/src/short_tests.rs b/evm-e2e/src/short_tests.rs index 5a5132ebc..32626e79f 100644 --- a/evm-e2e/src/short_tests.rs +++ b/evm-e2e/src/short_tests.rs @@ -11,6 +11,14 @@ macro_rules! define_tests { }; } +mod single_test { + define_tests! { + // fn transaction_create_auto_suicide_contract("tests/GeneralStateTests/stInitCodeTest/TransactionCreateAutoSuicideContract.json"); + // fn failed_tx_xcf416c53_paris("tests/GeneralStateTests/stSpecialTest/failed_tx_xcf416c53_Paris.json"); + fn precompile_absence("tests/GeneralStateTests/Pyspecs/frontier/precompiles/precompile_absence.json"); + } +} + mod good_coverage_tests { define_tests! { fn st_e_i_p3860_limitmeterinitcode_create_init_code_size_limit("tests/GeneralStateTests/Shanghai/stEIP3860-limitmeterinitcode/createInitCodeSizeLimit.json"); @@ -120,7 +128,7 @@ mod fails_with_stack_expansion { define_tests! { fn _15_tstore_cannot_be_dosd("tests/GeneralStateTests/Cancun/stEIP1153-transientStorage/15_tstoreCannotBeDosd.json"); fn _21_tstore_cannot_be_dosd_ooo("tests/GeneralStateTests/Cancun/stEIP1153-transientStorage/21_tstoreCannotBeDosdOOO.json"); - fn contract_creation_spam("tests/GeneralStateTests/stAttackTest/ContractCreationSpam.json"); + // fn contract_creation_spam("tests/GeneralStateTests/stAttackTest/ContractCreationSpam.json"); } } @@ -224,8 +232,24 @@ mod new_gas_model_failing_tests { } } -mod rwasm_stuck_tests { +mod rwasm_stuck_failing_tests { define_tests! { fn modexp("tests/GeneralStateTests/stPreCompiledContracts/modexp.json"); } } + +mod new_system_runtime_failing_tests { + define_tests! { + fn run_until_out_of_gas("tests/GeneralStateTests/Pyspecs/cancun/eip1153_tstore/run_until_out_of_gas.json"); + // fn contract_creation_spam("tests/GeneralStateTests/stAttackTest/ContractCreationSpam.json"); + fn opc_d9_diff_places("tests/GeneralStateTests/stBadOpcode/opcD9DiffPlaces.json"); + // fn call50000("tests/GeneralStateTests/stQuadraticComplexityTest/Call50000.json"); + // fn callcode50000("tests/GeneralStateTests/stQuadraticComplexityTest/Callcode50000.json"); + // fn static_call50000_identity("tests/GeneralStateTests/stStaticCall/static_Call50000_identity.json"); + fn abacalls2("tests/GeneralStateTests/stSystemOperationsTest/ABAcalls2.json"); + fn sstore_gas_left("tests/GeneralStateTests/stSStoreTest/sstore_gasLeft.json"); + fn call_oog_additional_gas_costs2("tests/GeneralStateTests/stCallCodes/call_OOG_additionalGasCosts2.json"); + // fn static_call1_mb1024_calldepth("tests/GeneralStateTests/stStaticCall/static_Call1MB1024Calldepth.json"); + // fn static_loop_calls_then_revert("tests/GeneralStateTests/stStaticCall/static_LoopCallsThenRevert.json"); + } +} diff --git a/evm-e2e/src/tests.rs b/evm-e2e/src/tests.rs index e372c9696..7ba61a038 100644 --- a/evm-e2e/src/tests.rs +++ b/evm-e2e/src/tests.rs @@ -381,7 +381,7 @@ mod st_args_zero_one_balance { mod st_attack_test { define_tests! { - fn contract_creation_spam("tests/GeneralStateTests/stAttackTest/ContractCreationSpam.json"); + // fn contract_creation_spam("tests/GeneralStateTests/stAttackTest/ContractCreationSpam.json"); fn crashing_transaction("tests/GeneralStateTests/stAttackTest/CrashingTransaction.json"); } } @@ -1368,7 +1368,7 @@ mod st_pre_compiled_contracts { fn delegatecall09_undefined("tests/GeneralStateTests/stPreCompiledContracts/delegatecall09Undefined.json"); fn identity_to_bigger("tests/GeneralStateTests/stPreCompiledContracts/identity_to_bigger.json"); fn identity_to_smaller("tests/GeneralStateTests/stPreCompiledContracts/identity_to_smaller.json"); - // fn modexp("tests/GeneralStateTests/stPreCompiledContracts/modexp.json"); + fn modexp("tests/GeneralStateTests/stPreCompiledContracts/modexp.json"); fn modexp_tests("tests/GeneralStateTests/stPreCompiledContracts/modexpTests.json"); // fn precomps_eip2929_cancun("tests/GeneralStateTests/stPreCompiledContracts/precompsEIP2929Cancun.json"); fn sec80("tests/GeneralStateTests/stPreCompiledContracts/sec80.json"); @@ -2282,7 +2282,7 @@ mod st_solidity_test { fn contract_inheritance("tests/GeneralStateTests/stSolidityTest/ContractInheritance.json"); fn create_contract_from_method("tests/GeneralStateTests/stSolidityTest/CreateContractFromMethod.json"); fn recursive_create_contracts("tests/GeneralStateTests/stSolidityTest/RecursiveCreateContracts.json"); - fn recursive_create_contracts_metadata_create_contracts("tests/GeneralStateTests/stSolidityTest/RecursiveCreateContractsCreate4Contracts.json"); + fn recursive_create_contracts_create4_contracts("tests/GeneralStateTests/stSolidityTest/RecursiveCreateContractsCreate4Contracts.json"); // fn self_destruct("tests/GeneralStateTests/stSolidityTest/SelfDestruct.json"); fn test_block_and_transaction_properties("tests/GeneralStateTests/stSolidityTest/TestBlockAndTransactionProperties.json"); fn test_contract_interaction("tests/GeneralStateTests/stSolidityTest/TestContractInteraction.json"); @@ -2355,12 +2355,12 @@ mod st_static_call { fn static_call1024_pre_calls("tests/GeneralStateTests/stStaticCall/static_Call1024PreCalls.json"); fn static_call1024_pre_calls2("tests/GeneralStateTests/stStaticCall/static_Call1024PreCalls2.json"); fn static_call1024_pre_calls3("tests/GeneralStateTests/stStaticCall/static_Call1024PreCalls3.json"); - fn static_call1_mb1024_calldepth("tests/GeneralStateTests/stStaticCall/static_Call1MB1024Calldepth.json"); + // fn static_call1_mb1024_calldepth("tests/GeneralStateTests/stStaticCall/static_Call1MB1024Calldepth.json"); // fn static_call50000("tests/GeneralStateTests/stStaticCall/static_Call50000.json"); // fn static_call50000_ecrec("tests/GeneralStateTests/stStaticCall/static_Call50000_ecrec.json"); - fn static_call50000_identity("tests/GeneralStateTests/stStaticCall/static_Call50000_identity.json"); + // fn static_call50000_identity("tests/GeneralStateTests/stStaticCall/static_Call50000_identity.json"); // fn static_call50000_identity2("tests/GeneralStateTests/stStaticCall/static_Call50000_identity2.json"); - fn static_call50000_rip160("tests/GeneralStateTests/stStaticCall/static_Call50000_rip160.json"); + // fn static_call50000_rip160("tests/GeneralStateTests/stStaticCall/static_Call50000_rip160.json"); fn static_call50000bytes_contract50_1("tests/GeneralStateTests/stStaticCall/static_Call50000bytesContract50_1.json"); fn static_call50000bytes_contract50_2("tests/GeneralStateTests/stStaticCall/static_Call50000bytesContract50_2.json"); fn static_call50000bytes_contract50_3("tests/GeneralStateTests/stStaticCall/static_Call50000bytesContract50_3.json"); @@ -2440,7 +2440,7 @@ mod st_static_call { fn static_loop_calls_depth_then_revert("tests/GeneralStateTests/stStaticCall/static_LoopCallsDepthThenRevert.json"); // fn static_loop_calls_depth_then_revert2("tests/GeneralStateTests/stStaticCall/static_LoopCallsDepthThenRevert2.json"); // fn static_loop_calls_depth_then_revert3("tests/GeneralStateTests/stStaticCall/static_LoopCallsDepthThenRevert3.json"); - fn static_loop_calls_then_revert("tests/GeneralStateTests/stStaticCall/static_LoopCallsThenRevert.json"); + // fn static_loop_calls_then_revert("tests/GeneralStateTests/stStaticCall/static_LoopCallsThenRevert.json"); fn static_post_to_return1("tests/GeneralStateTests/stStaticCall/static_PostToReturn1.json"); fn static_return_bounds("tests/GeneralStateTests/stStaticCall/static_RETURN_Bounds.json"); fn static_return_bounds_oog("tests/GeneralStateTests/stStaticCall/static_RETURN_BoundsOOG.json"); @@ -2739,7 +2739,7 @@ mod st_transaction_test { fn create_transaction_success("tests/GeneralStateTests/stTransactionTest/CreateTransactionSuccess.json"); fn empty_transaction3("tests/GeneralStateTests/stTransactionTest/EmptyTransaction3.json"); fn high_gas_limit("tests/GeneralStateTests/stTransactionTest/HighGasLimit.json"); - // fn high_gas_price_paris("tests/GeneralStateTests/stTransactionTest/HighGasPriceParis.json"); + fn high_gas_price_paris("tests/GeneralStateTests/stTransactionTest/HighGasPriceParis.json"); fn internal_call_hitting_gas_limit("tests/GeneralStateTests/stTransactionTest/InternalCallHittingGasLimit.json"); fn internal_call_hitting_gas_limit2("tests/GeneralStateTests/stTransactionTest/InternalCallHittingGasLimit2.json"); fn internal_call_hitting_gas_limit_success("tests/GeneralStateTests/stTransactionTest/InternalCallHittingGasLimitSuccess.json"); @@ -3150,3 +3150,4 @@ mod st_zero_knowledge2 { fn ecmul_1_2_2_21000_96("tests/GeneralStateTests/stZeroKnowledge2/ecmul_1-2_2_21000_96.json"); } } + diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 1074dcd5c..40c0b5a31 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.38" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fa99b538ca7006b0c03cfed24ec6d82beda67aac857ef4714be24231d15e6" +checksum = "07d9a64522a0db6ebcc4ff9c904e329e77dd737c2c25d30f1bdc32ca6c6ce334" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -114,7 +114,7 @@ dependencies = [ "derive_more 2.0.1", "foldhash 0.2.0", "hashbrown 0.16.0", - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "k256", "keccak-asm", @@ -147,14 +147,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "alloy-serde" -version = "1.0.38" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8468f1a7f9ee3bae73c24eead0239abea720dbf7779384b9c7e20d51bfb6b0" +checksum = "596cfa360922ba9af901cc7370c68640e4f72adb6df0ab064de32f21fec498d7" dependencies = [ "alloy-primitives", "serde", @@ -172,7 +172,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -185,11 +185,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.11.4", + "indexmap 2.12.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", "tiny-keccak", ] @@ -208,7 +208,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", ] @@ -248,6 +248,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object 0.32.2", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -384,7 +393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -422,7 +431,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -511,7 +520,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -564,7 +573,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -585,7 +594,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -680,11 +689,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -793,7 +802,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -828,9 +837,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.41" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "jobserver", @@ -1227,7 +1236,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1241,7 +1250,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1252,7 +1261,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1263,7 +1272,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1366,9 +1375,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1393,7 +1402,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1422,7 +1431,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1433,7 +1442,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "unicode-xid", ] @@ -1520,7 +1529,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1576,22 +1585,22 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1607,7 +1616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1680,7 +1689,7 @@ dependencies = [ "byteorder", "bytes", "fluentbase-codec-derive", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", ] @@ -1693,7 +1702,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1719,6 +1728,7 @@ dependencies = [ "revm-rwasm-context", "revm-rwasm-interpreter", "revm-rwasm-primitives", + "serde", ] [[package]] @@ -1835,7 +1845,7 @@ dependencies = [ "fluentbase-sdk", "fluentbase-testing", "hex", - "hex-literal 1.0.0", + "hex-literal 1.1.0", "libsecp256k1", "secp256k1-sys 0.10.1", "tiny-keccak", @@ -1915,6 +1925,7 @@ dependencies = [ name = "fluentbase-runtime" version = "0.4.11-dev" dependencies = [ + "anyhow", "blake3", "bytemuck", "fluentbase-types", @@ -1924,10 +1935,12 @@ dependencies = [ "rwasm", "schnellru", "sha2 0.10.9", + "smallvec", "snowbridge-amcl", "solana-poseidon", "sp1-curves", "tiny-keccak", + "wasmtime-rwasm", ] [[package]] @@ -1941,8 +1954,9 @@ dependencies = [ "fluentbase-crypto", "fluentbase-sdk-derive", "fluentbase-types", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "rwasm", + "spin 0.10.0", ] [[package]] @@ -1955,7 +1969,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1974,7 +1988,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.108", "syn-solidity", "thiserror 2.0.17", "tracing", @@ -1989,7 +2003,7 @@ dependencies = [ "fluentbase-revm", "fluentbase-runtime", "fluentbase-sdk", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hex", "revm-rwasm", "rwasm", @@ -2002,11 +2016,14 @@ dependencies = [ "alloy-primitives", "bincode 2.0.1", "byteorder", - "hashbrown 0.15.5", + "fluentbase-codec", + "fluentbase-codec-derive", + "hashbrown 0.16.0", "paste", "revm-rwasm-precompile", "revm-rwasm-primitives", "rwasm", + "serde", "strum_macros 0.27.2", ] @@ -2190,7 +2207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", - "indexmap 2.11.4", + "indexmap 2.12.0", "stable_deref_trait", ] @@ -2340,9 +2357,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hex-literal" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" [[package]] name = "hkdf" @@ -2436,7 +2453,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2452,9 +2469,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -2542,9 +2559,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -2714,7 +2731,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2822,7 +2839,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2893,9 +2910,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2903,14 +2920,23 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", ] [[package]] @@ -2921,7 +2947,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "memchr", ] @@ -3193,7 +3219,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3275,7 +3301,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3413,28 +3439,27 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", "bitflags", - "lazy_static", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -3447,10 +3472,11 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66fcd288453b748497d8fb18bccc83a16b0518e3906d4b8df0a8d42d93dbb1c" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" dependencies = [ + "ar_archive_writer", "cc", ] @@ -3474,7 +3500,7 @@ checksum = "9276d404009cc49f3b8befeb8ffc1d868c5ea732bd9d72ab3e64231187f908c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3640,7 +3666,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3980,7 +4006,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4052,7 +4078,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4078,9 +4104,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce" dependencies = [ "dyn-clone", "ref-cast", @@ -4220,7 +4246,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4229,7 +4255,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "memchr", "ryu", @@ -4248,17 +4274,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", + "schemars 1.0.5", "serde_core", "serde_json", "serde_with_macros", @@ -4267,14 +4293,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.15.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4299,7 +4325,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4359,8 +4385,8 @@ dependencies = [ [[package]] name = "shakmaty" -version = "0.29.3" -source = "git+https://github.com/niklasf/shakmaty#66dfd50143e8e15fd09791a81d453bf96028d30d" +version = "0.29.4" +source = "git+https://github.com/niklasf/shakmaty#a26c4866173715eec45c6412a83337e364518d47" dependencies = [ "arrayvec", "bitflags", @@ -4587,7 +4613,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4599,7 +4625,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4621,9 +4647,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -4639,7 +4665,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4679,7 +4705,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4717,7 +4743,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4728,7 +4754,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4816,7 +4842,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -4830,7 +4856,7 @@ version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "toml_datetime 0.7.3", "toml_parser", "winnow", @@ -4870,7 +4896,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4900,7 +4926,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4935,9 +4961,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -5017,9 +5043,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -5028,25 +5054,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5054,22 +5066,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -5151,7 +5163,7 @@ checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102" dependencies = [ "bitflags", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "semver 1.0.27", "serde", ] @@ -5163,7 +5175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" dependencies = [ "bitflags", - "indexmap 2.11.4", + "indexmap 2.12.0", "semver 1.0.27", ] @@ -5225,7 +5237,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -5253,7 +5265,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "smallvec", "target-lexicon", "thiserror 2.0.17", @@ -5274,9 +5286,9 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", - "object", + "object 0.36.7", "postcard", "rustc-demangle", "semver 1.0.27", @@ -5313,7 +5325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d83fa2dea686f76b5437b66045aae6351d359ee11cc4124f9842de63837b81" dependencies = [ "cc", - "object", + "object 0.36.7", "rustix", "wasmtime-versioned-export-macros", ] @@ -5356,13 +5368,13 @@ dependencies = [ "fxprof-processed-profile", "gimli", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.0", "ittapi", "libc", "log", "mach2", "memfd", - "object", + "object 0.36.7", "once_cell", "postcard", "psm", @@ -5411,7 +5423,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.36.7", "pulley-interpreter", "smallvec", "target-lexicon", @@ -5436,7 +5448,7 @@ checksum = "4e052e1d9c30b8f31aff64380caaaff492a9890a412658bcc8866fe626b8e91f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5448,7 +5460,7 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object", + "object 0.36.7", "target-lexicon", "wasmparser 0.233.0", "wasmtime-cranelift", @@ -5464,7 +5476,7 @@ checksum = "f967f5efaaac7694e6bd0d67542a5a036830860e4adf95684260181e85a5d299" dependencies = [ "anyhow", "heck", - "indexmap 2.11.4", + "indexmap 2.12.0", "wit-parser", ] @@ -5521,7 +5533,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5590,7 +5602,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5601,7 +5613,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5646,6 +5658,15 @@ dependencies = [ "windows-targets 0.53.5", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -5798,7 +5819,7 @@ checksum = "f22f1cd55247a2e616870b619766e9522df36b7abafbb29bbeb34b7a9da7e9f0" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", "semver 1.0.27", "serde", @@ -5834,7 +5855,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5854,7 +5875,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] diff --git a/examples/erc20/lib.rs b/examples/erc20/lib.rs index 688fce877..abe985aae 100644 --- a/examples/erc20/lib.rs +++ b/examples/erc20/lib.rs @@ -8,11 +8,10 @@ use alloc::{string::String, vec::Vec}; use alloy_sol_types::{sol, SolEvent}; use fluentbase_sdk::{ basic_entrypoint, - derive::{constructor, router, Storage}, + derive::{constructor, router, Contract}, storage::{StorageMap, StorageString, StorageU256}, Address, ContextReader, SharedAPI, B256, U256, }; -use fluentbase_sdk::derive::Contract; // Define the Transfer and Approval events sol! { @@ -200,7 +199,7 @@ basic_entrypoint!(ERC20); #[cfg(test)] mod tests { use super::*; - use fluentbase_sdk::{address, codec::Encoder, ContractContextV1, U256}; + use fluentbase_sdk::{address, ContractContextV1, U256}; use fluentbase_testing::HostTestingContext; #[test]