diff --git a/Cargo.lock b/Cargo.lock index 10205ee4ea..bedbfa5486 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,10 +118,22 @@ version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" dependencies = [ - "funty", + "funty 1.1.0", "radium 0.6.2", "tap", - "wyz", + "wyz 0.2.0", +] + +[[package]] +name = "bitvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" +dependencies = [ + "funty 2.0.0", + "radium 0.7.0", + "tap", + "wyz 0.5.0", ] [[package]] @@ -151,13 +163,13 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bn-rs" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793f50e2b13c6a643603824994d9c992d41112e4293fb83307ee71e20a5dff1d" +checksum = "55f9480d25c1283e8806b280f65e885b4fb840e8e8d72b784401233c9bd83202" dependencies = [ "getrandom 0.2.3", "js-sys", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "rustc-hex", "thiserror", "uint", @@ -323,17 +335,6 @@ dependencies = [ "const-oid", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "derive_more" version = "0.99.16" @@ -441,11 +442,10 @@ dependencies = [ [[package]] name = "ethabi" -version = "14.1.0" +version = "16.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01317735d563b3bad2d5f90d2e1799f414165408251abb762510f40e790e69a" +checksum = "a4c98847055d934070b90e806e12d3936b787d0a115068981c1d8dfd5dfef5a5" dependencies = [ - "anyhow", "ethereum-types", "hex", "serde", @@ -470,15 +470,15 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64b5df66a228d85e4b17e5d6c6aa43b0310898ffe8a85988c4c032357aaabfd" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" dependencies = [ "ethbloom", "fixed-hash", "impl-rlp", "impl-serde", - "primitive-types 0.9.1", + "primitive-types 0.10.1", "uint", ] @@ -494,12 +494,12 @@ dependencies = [ [[package]] name = "filedescriptor" -version = "0.7.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cb4dda2f343f3b7a98a6536559d04a700136cada190822e5d6a99e4184c06" +checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e" dependencies = [ - "anyhow", "libc", + "thiserror", "winapi", ] @@ -552,6 +552,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.17" @@ -799,7 +805,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 0.4.8", ] [[package]] @@ -840,7 +846,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.8", "pin-project-lite", "socket2", "tokio", @@ -882,6 +888,15 @@ dependencies = [ "parity-scale-codec 2.3.1", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec 3.0.0", +] + [[package]] name = "impl-rlp" version = "0.3.0" @@ -963,6 +978,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "js-sys" version = "0.3.55" @@ -1023,9 +1044,9 @@ checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -1227,19 +1248,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1329,7 +1349,21 @@ dependencies = [ "bitvec 0.20.4", "byte-slice-cast 1.2.0", "impl-trait-for-tuples", - "parity-scale-codec-derive", + "parity-scale-codec-derive 2.3.1", + "serde", +] + +[[package]] +name = "parity-scale-codec" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7f3fcf5e45fc28b84dcdab6b983e77f197ec01f325a33f404ba6855afd1070" +dependencies = [ + "arrayvec 0.7.2", + "bitvec 1.0.0", + "byte-slice-cast 1.2.0", + "impl-trait-for-tuples", + "parity-scale-codec-derive 3.0.0", "serde", ] @@ -1345,6 +1379,18 @@ dependencies = [ "syn", ] +[[package]] +name = "parity-scale-codec-derive" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6e626dc84025ff56bf1476ed0e30d10c84d7f89a475ef46ebabee1095a8fba" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1353,7 +1399,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.1", ] [[package]] @@ -1370,6 +1426,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1478,12 +1547,12 @@ checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "primitive-types" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06345ee39fbccfb06ab45f3a1a5798d9dafa04cb8921a76d227040003a234b0e" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ "fixed-hash", - "impl-codec", + "impl-codec 0.5.1", "impl-rlp", "impl-serde", "uint", @@ -1491,12 +1560,12 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ "fixed-hash", - "impl-codec", + "impl-codec 0.6.0", "impl-rlp", "impl-serde", "uint", @@ -1566,6 +1635,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -1748,8 +1823,8 @@ dependencies = [ "hashbrown 0.12.0", "hex", "num_enum", - "parking_lot", - "primitive-types 0.10.1", + "parking_lot 0.12.0", + "primitive-types 0.11.1", "revm_precompiles", "rlp", "sha3 0.10.0", @@ -1764,7 +1839,7 @@ version = "0.1.0" dependencies = [ "bytes", "hex", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "revm", ] @@ -1776,10 +1851,10 @@ dependencies = [ "hex", "k256", "num", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "ripemd", - "secp256k1 0.21.2", - "sha2", + "secp256k1", + "sha2 0.10.1", "sha3 0.10.0", "substrate-bn", ] @@ -1794,7 +1869,7 @@ dependencies = [ "hex", "indicatif", "plain_hasher", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "revm", "rlp", "serde", @@ -1817,7 +1892,7 @@ dependencies = [ "getrandom 0.2.3", "hex", "js-sys", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "revm", "wasm-bindgen", ] @@ -1910,15 +1985,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" -dependencies = [ - "secp256k1-sys", -] - [[package]] name = "secp256k1" version = "0.21.2" @@ -1980,18 +2046,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -2000,11 +2066,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -2016,7 +2082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -2034,6 +2100,19 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.1" @@ -2126,9 +2205,9 @@ dependencies = [ [[package]] name = "soketto" -version = "0.5.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4919971d141dbadaa0e82b5d369e2d7666c98e4625046140615ca363e50d4daa" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64", "bytes", @@ -2265,15 +2344,16 @@ dependencies = [ [[package]] name = "termwiz" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b348dd979d43d0082d232b0e7ff03b95a3eca71a96b230aba855ad86273c33" +checksum = "31ef6892cc0348a9b3b8c377addba91e0f6365863d92354bf27559dca81ee8c5" dependencies = [ "anyhow", "base64", "bitflags", "cfg-if 1.0.0", "filedescriptor", + "hex", "lazy_static", "libc", "log", @@ -2283,15 +2363,15 @@ dependencies = [ "ordered-float", "regex", "semver", + "sha2 0.9.9", "signal-hook", "terminfo", "termios", "thiserror", + "ucd-trie", "unicode-segmentation", - "unicode-width", "vtparse", "winapi", - "xi-unicode", ] [[package]] @@ -2349,18 +2429,17 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.14.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" dependencies = [ - "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", "once_cell", - "parking_lot", + "parking_lot 0.11.2", "pin-project-lite", "signal-hook-registry", "tokio-macros", @@ -2369,9 +2448,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -2560,9 +2639,9 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "vtparse" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a0bebf506b5405df1bc773d1b7bfa5d2fb11011b8c95b7d0a6dfd0f8f37142" +checksum = "8f41c9314c4dde1f43dd0c46c67bb5ae73850ce11eebaf7d8b912e178bda5401" dependencies = [ "utf8parse", ] @@ -2678,11 +2757,11 @@ dependencies = [ [[package]] name = "web3" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd24abe6f2b68e0677f843059faea87bcbd4892e39f02886f366d8222c3c540d" +checksum = "44f258e254752d210b84fe117b31f1e3cc9cbf04c0d747eb7f8cf7cf5e370f6d" dependencies = [ - "arrayvec 0.5.2", + "arrayvec 0.7.2", "base64", "bytes", "derive_more", @@ -2692,13 +2771,15 @@ dependencies = [ "futures-timer", "headers", "hex", + "idna", "jsonrpc-core", "log", - "parking_lot", + "once_cell", + "parking_lot 0.12.0", "pin-project", "reqwest", "rlp", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_json", "soketto", @@ -2753,6 +2834,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "winreg" version = "0.7.0" @@ -2769,10 +2893,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] -name = "xi-unicode" -version = "0.3.0" +name = "wyz" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] [[package]] name = "zeroize" diff --git a/README.md b/README.md index 4b67737068..22eb71bc41 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # revm - Revolutionary Machine -Is **Rust Ethereum Virtual Machine** with great name that is focused on **speed** and **simplicity**. It gets ispiration from `SputnikVM` (got opcodes/machine from here), `OpenEthereum` and `Geth` with a help from [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes). +Is **Rust Ethereum Virtual Machine** with great name that is focused on **speed** and **simplicity**. It gets ispiration from `SputnikVM` (got opcodes/interp from here), `OpenEthereum` and `Geth` with a help from [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes). It is fast and flexible implementation of EVM with simple interface and embeded Host, there are multiple things done on Host part from const EVM Spec to optimistic changelogs for subroutines to merging `eip2929` in EVM state so that it can be accesses only once that are improving the speed of execution. There are still some improvements on Interepter part that needs to be done so that we can be comparable with evmone, for more info track [this issue](https://github.com/bluealloy/revm/issues/7). diff --git a/bins/revm-test/Cargo.toml b/bins/revm-test/Cargo.toml index 1bd35a164c..5052373a9e 100644 --- a/bins/revm-test/Cargo.toml +++ b/bins/revm-test/Cargo.toml @@ -7,5 +7,5 @@ edition = "2018" [dependencies] bytes = "1.1" hex = "0.4" -primitive-types = { version = "0.10", features = ["rlp"] } +primitive-types = { version = "0.11", features = ["rlp"] } revm = { path = "../../crates/revm" } diff --git a/bins/revm-test/src/main.rs b/bins/revm-test/src/main.rs index 1d2a5dcee8..167ff55502 100644 --- a/bins/revm-test/src/main.rs +++ b/bins/revm-test/src/main.rs @@ -21,14 +21,14 @@ pub fn simple_example() { let mut elapsed = std::time::Duration::ZERO; let mut times = Vec::new(); - for _ in 0..10 { + for _ in 0..30 { let timer = Instant::now(); let (_, _, _, _, _) = evm.transact(); let i = timer.elapsed(); times.push(i); elapsed += i; } - println!("elapsed: {:?}", elapsed / 10); + println!("elapsed: {:?}", elapsed / 30); for (i, time) in times.iter().enumerate() { println!("{}: {:?}", i, time); } diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index b635d76088..98bed35137 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -16,7 +16,7 @@ hashbrown = "0.12" hex = "0.4" indicatif = "0.16" plain_hasher = "0.2" -primitive-types = { version = "0.10", features = ["rlp", "serde"] } +primitive-types = { version = "0.11", features = ["rlp", "serde"] } revm = { path = "../../crates/revm", version = "1.1", default-features = false, features = ["web3db","std","k256"] } rlp = { version = "0.5", default-features = false } @@ -25,7 +25,7 @@ serde_derive = "1.0" serde_json = "1.0" sha3 = { version = "0.10", default-features = false } structopt = "0.3" -termwiz = "0.13" # used for debugger ctrl +termwiz = "0.15" # used for debugger ctrl thiserror = "1.0" triehash = "0.8" walkdir = "2.3" diff --git a/bins/revme/src/debugger/ctrl/ctrl.rs b/bins/revme/src/debugger/ctrl/ctrl.rs index 60e8be2654..b46460e167 100644 --- a/bins/revme/src/debugger/ctrl/ctrl.rs +++ b/bins/revme/src/debugger/ctrl/ctrl.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use bytes::Bytes; use primitive_types::{H160, U256}; -use revm::{Database, EVMData, Gas, Inspector, Return, OPCODE_JUMPMAP}; +use revm::{CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Return, OPCODE_JUMPMAP}; use termwiz::lineedit::*; @@ -90,7 +90,7 @@ pub enum StateMachine { } pub struct Controller { - state_machine: StateMachine, + state_interp: StateMachine, history_path: Option, //call_stack: Vec<>, } @@ -98,7 +98,7 @@ pub struct Controller { impl Controller { pub fn new(history_path: Option) -> Self { Self { - state_machine: StateMachine::TriggerStep, + state_interp: StateMachine::TriggerStep, history_path, } } @@ -108,73 +108,69 @@ impl Controller { impl Inspector for Controller { fn step( &mut self, - machine: &mut revm::Machine, + interp: &mut revm::Interpreter, data: &mut EVMData<'_, DB>, _is_static: bool, ) -> Return { loop { - match Ctrl::next(self.state_machine, &self.history_path) { + match Ctrl::next(self.state_interp, &self.history_path) { Ctrl::Help => { println!( "available controls: \nstep\nexit\nprint all\nstack pop\nstack push 10\n" ) } Ctrl::Exit => { - self.state_machine = StateMachine::Exit; + self.state_interp = StateMachine::Exit; break; } Ctrl::Step => { - self.state_machine = StateMachine::TriggerStep; + self.state_interp = StateMachine::TriggerStep; break; } //Ctrl::StepIn => {} //Ctrl::StepOut => { - // self.state_machine = StateMachine::StepOut; + // self.state_interp = StateMachine::StepOut; //} Ctrl::Print(print) => match print { CtrlPrint::All => { - let opcode = machine + let opcode = interp .contract .code - .get(machine.program_counter()) + .get(interp.program_counter()) .cloned() .unwrap(); - let gas_spend = machine.gas().spend(); - let gas_remaining = machine.gas().remaining(); + let gas_spend = interp.gas().spend(); + let gas_remaining = interp.gas().remaining(); println!( "call_depth:{} PC:{} Opcode: {:#x} {:?} gas(spend,remaining):({},{})\n\ Stack:{}", - machine.call_depth, - machine.program_counter(), + interp.call_depth, + interp.program_counter(), opcode, OPCODE_JUMPMAP[opcode as usize].unwrap_or("Invalid"), gas_spend, gas_remaining, - machine.stack(), + interp.stack(), ); } CtrlPrint::Opcode => { - let opcode = *machine - .contract - .code - .get(machine.program_counter()) - .unwrap(); + let opcode = *interp.contract.code.get(interp.program_counter()).unwrap(); println!( "PC:{} OpCode: {:#x} {:?}", - machine.program_counter(), + interp.program_counter(), opcode, OPCODE_JUMPMAP[opcode as usize] ) } CtrlPrint::Stack => { - println!("PC:{} stack:{}", machine.program_counter(), machine.stack()) + println!("PC:{} stack:{}", interp.program_counter(), interp.stack()) } CtrlPrint::Memory => { - println!("memory:{}", hex::encode(&machine.memory.data())) + println!("memory:{}", hex::encode(&interp.memory.data())) } }, Ctrl::Continue => { - self.state_machine = StateMachine::TriggerBreakpoint; + self.state_interp = StateMachine::TriggerBreakpoint; break; } Ctrl::Restart => { @@ -190,10 +186,10 @@ impl Inspector for Controller { } Ctrl::AccountPrintOriginal(_address) => (), Ctrl::StackPop => { - println!("pop:{:?}", machine.stack.pop()); + println!("pop:{:?}", interp.stack.pop()); } - Ctrl::StackPush(value) => match machine.stack.push(value) { - Ok(()) => println!("stack:{}", machine.stack()), + Ctrl::StackPush(value) => match interp.stack.push(value) { + Ok(()) => println!("stack:{}", interp.stack()), Err(e) => println!("push error:{:?}", e), }, Ctrl::None => break, @@ -202,18 +198,20 @@ impl Inspector for Controller { Return::Continue } - fn step_end(&mut self, _eval: revm::Return, _machine: &mut revm::Machine) -> Return { + fn step_end( + &mut self, + _interp: &mut revm::Interpreter, + _data: &mut EVMData<'_, DB>, + _is_static: bool, + _eval: revm::Return, + ) -> Return { Return::Continue } fn call( &mut self, _data: &mut revm::EVMData<'_, DB>, - _call: primitive_types::H160, - _context: &revm::CallContext, - _transfer: &revm::Transfer, - _input: &bytes::Bytes, - _gas_limit: u64, + _inputs: &CallInputs, _is_static: bool, ) -> (Return, Gas, Bytes) { (Return::Continue, Gas::new(0), Bytes::new()) @@ -222,29 +220,21 @@ impl Inspector for Controller { fn call_end( &mut self, _data: &mut EVMData<'_, DB>, - _call: H160, - _context: &revm::CallContext, - _transfer: &revm::Transfer, - _input: &Bytes, - _gas_limit: u64, - _remaining_gas: u64, + _inputs: &CallInputs, + _remaining_gas: Gas, _ret: Return, _out: &Bytes, _is_static: bool, ) { - if let StateMachine::StepOut = self.state_machine { - self.state_machine = StateMachine::TriggerStep + if let StateMachine::StepOut = self.state_interp { + self.state_interp = StateMachine::TriggerStep } } fn create( &mut self, _data: &mut revm::EVMData<'_, DB>, - _caller: primitive_types::H160, - _scheme: &revm::CreateScheme, - _value: primitive_types::U256, - _init_code: &bytes::Bytes, - _gas: u64, + _inputs: &CreateInputs, ) -> (Return, Option, Gas, Bytes) { (Return::Continue, None, Gas::new(0), Bytes::new()) } @@ -252,18 +242,14 @@ impl Inspector for Controller { fn create_end( &mut self, _data: &mut EVMData<'_, DB>, - _caller: H160, - _scheme: &revm::CreateScheme, - _value: U256, - _init_code: &Bytes, + _inputs: &CreateInputs, _ret: Return, _address: Option, - _gas_limit: u64, - _remaining_gas: u64, + _remaining_gas: Gas, _out: &Bytes, ) { - if let StateMachine::StepOut = self.state_machine { - self.state_machine = StateMachine::TriggerStep + if let StateMachine::StepOut = self.state_interp { + self.state_interp = StateMachine::TriggerStep } } diff --git a/bins/revme/src/statetest/trace.rs b/bins/revme/src/statetest/trace.rs index e1345b1334..b5611da755 100644 --- a/bins/revme/src/statetest/trace.rs +++ b/bins/revme/src/statetest/trace.rs @@ -1,12 +1,12 @@ use bytes::Bytes; -use primitive_types::{H160, U256}; +use primitive_types::H160; pub use revm::Inspector; -use revm::{opcode, spec_opcode_gas, Database, EVMData, Gas, Return}; +use revm::{opcode, spec_opcode_gas, CallInputs, CreateInputs, Database, EVMData, Gas, Return}; #[derive(Clone)] pub struct CustomPrintTracer { /// We now batch continual gas_block in one go, that means we need to reduce it ifwe want to get - /// correct gas remaining. Check revm/machine/contract/analize for more information + /// correct gas remaining. Check revm/interp/contract/analize for more information reduced_gas_block: u64, full_gas_block: u64, } @@ -21,27 +21,27 @@ impl CustomPrintTracer { } impl Inspector for CustomPrintTracer { - fn initialize_machine( + fn initialize_interp( &mut self, - machine: &mut revm::Machine, + interp: &mut revm::Interpreter, _data: &mut EVMData<'_, DB>, _is_static: bool, ) -> Return { - self.full_gas_block = machine.contract.first_gas_block(); + self.full_gas_block = interp.contract.first_gas_block(); Return::Continue } - // get opcode by calling `machine.contract.opcode(machine.program_counter())`. - // all other information can be obtained from machine. + // get opcode by calling `interp.contract.opcode(interp.program_counter())`. + // all other information can be obtained from interp. fn step( &mut self, - machine: &mut revm::Machine, + interp: &mut revm::Interpreter, data: &mut EVMData<'_, DB>, _is_static: bool, ) -> Return { // Safety: casting. In analazis we are making this clame true that program counter will always // point to bytecode of the contract. - let opcode = unsafe { *machine.program_counter }; + let opcode = unsafe { *interp.program_counter }; let opcode_str = opcode::OPCODE_JUMPMAP[opcode as usize]; // calculate gas_block @@ -50,21 +50,21 @@ impl Inspector for CustomPrintTracer { println!( "depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data:", - machine.call_depth, - machine.program_counter(), - machine.gas.remaining()+self.full_gas_block-self.reduced_gas_block, - machine.gas.remaining()+self.full_gas_block-self.reduced_gas_block, + interp.call_depth, + interp.program_counter(), + interp.gas.remaining()+self.full_gas_block-self.reduced_gas_block, + interp.gas.remaining()+self.full_gas_block-self.reduced_gas_block, opcode_str.unwrap(), opcode, - machine.gas.refunded(), - machine.gas.refunded(), - machine.stack.data(), - //hex::encode(machine.memory.data()), + interp.gas.refunded(), + interp.gas.refunded(), + interp.stack.data(), + //hex::encode(interp.memory.data()), ); if info.gas_block_end { self.reduced_gas_block = 0; - self.full_gas_block = machine.contract.gas_block(machine.program_counter()); + self.full_gas_block = interp.contract.gas_block(interp.program_counter()); } else { self.reduced_gas_block += info.gas; } @@ -72,53 +72,29 @@ impl Inspector for CustomPrintTracer { Return::Continue } - // fn load_account(&mut self, address: &H160) { - // println!("ACCOUNT LOADED:{:?}", address); - // } - - fn step_end(&mut self, _eval: revm::Return, _machine: &mut revm::Machine) -> Return { + fn step_end( + &mut self, + _interp: &mut revm::Interpreter, + _data: &mut EVMData<'_, DB>, + _is_static: bool, + _eval: revm::Return, + ) -> Return { Return::Continue } - // fn sload(&mut self, address: &H160, slot: &U256, value: &U256, is_cold: bool) { - // println!( - // "sload: is_cold({}) {}[{:?}]={:?}", - // is_cold, address, slot, value - // ); - // } - - // fn sstore( - // &mut self, - // address: H160, - // slot: U256, - // new_value: U256, - // old_value: U256, - // original_value: U256, - // is_cold: bool, - // ) { - // println!( - // "sstore: is_cold({}) {}[{:?}] {:?}(original:{:?}) => {:?}", - // is_cold, address, slot, old_value, original_value, new_value - // ); - // } - fn call( &mut self, _data: &mut EVMData<'_, DB>, - call: H160, - context: &revm::CallContext, - transfer: &revm::Transfer, - input: &bytes::Bytes, - _gas_limit: u64, + inputs: &CallInputs, is_static: bool, ) -> (Return, Gas, Bytes) { println!( "SM CALL: {:?},context:{:?}, is_static:{:?}, transfer:{:?}, input:{:?}", - call, - context, + inputs.contract, + inputs.context, is_static, - transfer, - hex::encode(input), + inputs.transfer, + hex::encode(&inputs.input), ); (Return::Continue, Gas::new(0), Bytes::new()) } @@ -126,12 +102,8 @@ impl Inspector for CustomPrintTracer { fn call_end( &mut self, _data: &mut EVMData<'_, DB>, - _call: H160, - _context: &revm::CallContext, - _transfer: &revm::Transfer, - _input: &Bytes, - _gas_limit: u64, - _remaining_gas: u64, + _inputs: &CallInputs, + _remaining_gas: Gas, _ret: Return, _out: &Bytes, _is_static: bool, @@ -141,19 +113,15 @@ impl Inspector for CustomPrintTracer { fn create( &mut self, _data: &mut EVMData<'_, DB>, - caller: H160, - scheme: &revm::CreateScheme, - value: U256, - init_code: &bytes::Bytes, - gas: u64, + inputs: &CreateInputs, ) -> (Return, Option, Gas, Bytes) { println!( "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}", - caller, - scheme, - value, - hex::encode(init_code), - gas + inputs.caller, + inputs.scheme, + inputs.value, + hex::encode(&inputs.init_code), + inputs.gas_limit ); (Return::Continue, None, Gas::new(0), Bytes::new()) } @@ -161,14 +129,10 @@ impl Inspector for CustomPrintTracer { fn create_end( &mut self, _data: &mut EVMData<'_, DB>, - _caller: H160, - _scheme: &revm::CreateScheme, - _value: U256, - _init_code: &Bytes, + _inputs: &CreateInputs, _ret: Return, _address: Option, - _gas_limit: u64, - _remaining_gas: u64, + _remaining_gas: Gas, _out: &Bytes, ) { } diff --git a/crates/revm/CHANGELOG.md b/crates/revm/CHANGELOG.md index bccf75070f..7e2877932d 100644 --- a/crates/revm/CHANGELOG.md +++ b/crates/revm/CHANGELOG.md @@ -32,7 +32,7 @@ Optimization thread: https://github.com/bluealloy/revm/issues/7 # v0.5.0 date: 17.11.2021 -A lot of optimization on machine(interpreter) part, it is now at least 3x faster. On interface side, Error enum was renamed to Return and it is simplified. Additionally if needed gas measuring can be removed with rust feature. +A lot of optimization on machine(Interpreter) part, it is now at least 3x faster. On interface side, Error enum was renamed to Return and it is simplified. Additionally if needed gas measuring can be removed with rust feature. Changes: * push instruction optimized. diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 966fac6884..0300fefda6 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ["Dragan Rakita "] -description = "REVM - Rust Ethereum virtual machine" +description = "REVM - Rust Ethereum virtual interp" edition = "2018" keywords = ["no_std", "ethereum", "evm"] license = "MIT" @@ -16,13 +16,13 @@ bytes = { version = "1.1", default-features = false } futures = { version = "0.3.17", optional = true } hashbrown = { version = "0.12" } num_enum = { version = "0.5", default-features = false }#used for SpecId from u8 cast -parking_lot = { version = "0.11.2", optional = true } -primitive-types = { version = "0.10", default-features = false, features = ["rlp"] } +parking_lot = { version = "0.12", optional = true } +primitive-types = { version = "0.11", default-features = false, features = ["rlp"] } revm_precompiles = { path = "../revm_precompiles", version = "0.4", default-features = false } rlp = { version = "0.5", default-features = false }#used for create2 address calculation sha3 = { version = "0.10", default-features = false } tokio = { version = "1.14", features = ["rt-multi-thread", "macros"], optional = true } -web3 = { version = "0.17", optional = true } +web3 = { version = "0.18", optional = true } #crypto-bigint = "0.3" zkp-u256 = "0.2.1" diff --git a/crates/revm/README.md b/crates/revm/README.md index 59ba64daea..cd17c53a92 100644 --- a/crates/revm/README.md +++ b/crates/revm/README.md @@ -1,6 +1,6 @@ # revm - Revolutionary Machine -Is **Rust Ethereum Virtual Machine** with great name that is focused on **speed** and **simplicity**. It gets ispiration from `SputnikVM` (got opcodes/machine from here), `OpenEthereum` and `Geth` with a help from [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes). This is probably one of the fastest implementation of EVM, from const EVM Spec to optimistic changelogs for subroutines to merging `eip2929` in EVM state so that it can be accesses only once are some of the things that are improving the speed of execution. +Is **Rust Ethereum Virtual Machine** with great name that is focused on **speed** and **simplicity**. It gets ispiration from `SputnikVM` (got opcodes/interp from here), `OpenEthereum` and `Geth` with a help from [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes). This is probably one of the fastest implementation of EVM, from const EVM Spec to optimistic changelogs for subroutines to merging `eip2929` in EVM state so that it can be accesses only once are some of the things that are improving the speed of execution. Here is list of things that i would like to use as guide in this project: - **EVM compatibility and stability** - this goes without saying but it is nice to put it here. In blockchain industry, stability is most desired attribute of any system. @@ -73,9 +73,9 @@ I just started this project as a hobby to kill some time. Presenty it has good s The structure of the project is getting crystallized and we can see few parts that are worthy to write about: - `Spec` contains a specification of Ethereum standard. It is made as a trait so that it can be optimized away by the compiler - `instructions` have one main function `eval` and takes `Machine`, `EVM Host`, `Spec` and `opcode` and depending on opcode it does calculation or for various opcodes it call `Host` for subroutine handling. This is where execution happens and where we cancluate gas consumption. -- `machine` contains memory and execution stack of smart contracts. It calls opcode for execution and contains `step` function. It reads the contract, extracts opcodes and handles memory. -- `subroutine` for various calls/creates we need to have separate `machine` and separate accessed locations. This is place where all of this is done, additionaly, it contains all caches of accessed accounts/slots/code. EIP2929 related access is integrated into state memory. Getting inside new call `subroutine` creates checkpoint that contain needed information that can revert state if subcall reverts or needs to be discardet. Changeset is made so it is optimistic that means that we dont do any work if call is finished successfully and only do something when it fials. -- `EVMImpl`- Is main entry to the lib,it implements `Host` and connects `subroutine` and `machine` and does `subroutine checkpoint` switches. +- `interp` contains memory and execution stack of smart contracts. It calls opcode for execution and contains `step` function. It reads the contract, extracts opcodes and handles memory. +- `subroutine` for various calls/creates we need to have separate `interp` and separate accessed locations. This is place where all of this is done, additionaly, it contains all caches of accessed accounts/slots/code. EIP2929 related access is integrated into state memory. Getting inside new call `subroutine` creates checkpoint that contain needed information that can revert state if subcall reverts or needs to be discardet. Changeset is made so it is optimistic that means that we dont do any work if call is finished successfully and only do something when it fials. +- `EVMImpl`- Is main entry to the lib,it implements `Host` and connects `subroutine` and `interp` and does `subroutine checkpoint` switches. ### Subroutine diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index d081488abf..24649861e0 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1,14 +1,13 @@ use crate::{ db::Database, - instructions::gas, - machine, - machine::{Contract, Gas, Machine}, + gas, interpreter, + interpreter::{Contract, Interpreter}, models::SelfDestructResult, return_ok, - spec::{Spec, SpecId::*}, subroutine::{Account, State, SubRoutine}, - util, CallContext, CreateScheme, Env, Inspector, Log, Return, TransactOut, TransactTo, - Transfer, KECCAK_EMPTY, + CallContext, CallInputs, CreateInputs, CreateScheme, Env, Gas, Inspector, Log, Return, Spec, + SpecId::*, + TransactOut, TransactTo, Transfer, KECCAK_EMPTY, }; use alloc::vec::Vec; use bytes::Bytes; @@ -118,22 +117,29 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact address, apparent_value: value, }; - let (exit, gas, bytes) = self.call_inner::( - address, - Transfer { + let call_input = CallInputs { + contract: address, + transfer: Transfer { source: caller, target: address, value, }, - data, + input: data, gas_limit, context, - ); + }; + let (exit, gas, bytes) = self.call_inner::(&call_input); (exit, gas, TransactOut::Call(bytes)) } TransactTo::Create(scheme) => { - let (exit, address, ret_gas, bytes) = - self.create_inner::(caller, scheme, value, data, gas_limit); + let create_input = CreateInputs { + caller, + scheme, + value, + init_code: data, + gas_limit, + }; + let (exit, address, ret_gas, bytes) = self.create_inner::(&create_input); (exit, ret_gas, TransactOut::Create(bytes, address)) } }; @@ -285,31 +291,27 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, fn create_inner( &mut self, - caller: H160, - scheme: CreateScheme, - value: U256, - init_code: Bytes, - gas_limit: u64, + inputs: &CreateInputs, ) -> (Return, Option, Gas, Bytes) { - let gas = Gas::new(gas_limit); - self.load_account(caller); + let gas = Gas::new(inputs.gas_limit); + self.load_account(inputs.caller); // check depth of calls - if self.data.subroutine.depth() > machine::CALL_STACK_LIMIT { + if self.data.subroutine.depth() > interpreter::CALL_STACK_LIMIT { return (Return::CallTooDeep, None, gas, Bytes::new()); } // check balance of caller and value. Do this before increasing nonce - if self.balance(caller).0 < value { + if self.balance(inputs.caller).0 < inputs.value { return (Return::OutOfFund, None, gas, Bytes::new()); } // inc nonce of caller - let old_nonce = self.data.subroutine.inc_nonce(caller); + let old_nonce = self.data.subroutine.inc_nonce(inputs.caller); // create address - let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice()); - let created_address = match scheme { - CreateScheme::Create => util::create_address(caller, old_nonce), - CreateScheme::Create2 { salt } => util::create2_address(caller, code_hash, salt), + let code_hash = H256::from_slice(Keccak256::digest(&inputs.init_code).as_slice()); + let created_address = match inputs.scheme { + CreateScheme::Create => create_address(inputs.caller, old_nonce), + CreateScheme::Create2 { salt } => create2_address(inputs.caller, code_hash, salt), }; let ret = Some(created_address); @@ -330,11 +332,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } // transfer value to contract address - if let Err(e) = self - .data - .subroutine - .transfer(caller, created_address, value, self.data.db) - { + if let Err(e) = self.data.subroutine.transfer( + inputs.caller, + created_address, + inputs.value, + self.data.db, + ) { self.data.subroutine.checkpoint_revert(checkpoint); return (e, ret, gas, Bytes::new()); } @@ -342,26 +345,32 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, if SPEC::enabled(ISTANBUL) { self.data.subroutine.inc_nonce(created_address); } - // create new machine and execute init function - let contract = - Contract::new::(Bytes::new(), init_code, created_address, caller, value); - let mut machine = Machine::new::(contract, gas.limit(), self.data.subroutine.depth()); + // create new interp and execute init function + let contract = Contract::new::( + Bytes::new(), + inputs.init_code.clone(), + created_address, + inputs.caller, + inputs.value, + ); + let mut interp = + Interpreter::new::(contract, gas.limit(), self.data.subroutine.depth()); if Self::INSPECT { self.inspector - .initialize_machine(&mut machine, &mut self.data, false); // TODO fix is_static + .initialize_interp(&mut interp, &mut self.data, false); // TODO fix is_static } - let exit_reason = machine.run::(self); + let exit_reason = interp.run::(self); // Host error if present on execution\ let ret = match exit_reason { return_ok!() => { let b = Bytes::new(); // if ok, check contract creation limit and calculate gas deduction on output len. - let code = machine.return_value(); + let code = interp.return_value(); // EIP-3541: Reject new contract code starting with the 0xEF byte if SPEC::enabled(LONDON) && !code.is_empty() && code.get(0) == Some(&0xEF) { self.data.subroutine.checkpoint_revert(checkpoint); - return (Return::CreateContractWithEF, ret, machine.gas, b); + return (Return::CreateContractWithEF, ret, interp.gas, b); } // TODO maybe create some macro to hide this `if` @@ -375,14 +384,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, // EIP-170: Contract code size limit if SPEC::enabled(SPURIOUS_DRAGON) && code.len() > contract_code_size_limit { self.data.subroutine.checkpoint_revert(checkpoint); - return (Return::CreateContractLimit, ret, machine.gas, b); + return (Return::CreateContractLimit, ret, interp.gas, b); } if crate::USE_GAS { - let gas_for_code = code.len() as u64 * crate::instructions::gas::CODEDEPOSIT; + let gas_for_code = code.len() as u64 * crate::gas::CODEDEPOSIT; // record code deposit gas cost and check if we are out of gas. - if !machine.gas.record_cost(gas_for_code) { + if !interp.gas.record_cost(gas_for_code) { self.data.subroutine.checkpoint_revert(checkpoint); - return (Return::OutOfGas, ret, machine.gas, b); + return (Return::OutOfGas, ret, interp.gas, b); } } // if we have enought gas @@ -391,49 +400,42 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, self.data .subroutine .set_code(created_address, code, code_hash); - (Return::Continue, ret, machine.gas, b) + (Return::Continue, ret, interp.gas, b) } _ => { self.data.subroutine.checkpoint_revert(checkpoint); - (exit_reason, ret, machine.gas, machine.return_value()) + (exit_reason, ret, interp.gas, interp.return_value()) } }; ret } #[allow(clippy::too_many_arguments)] - fn call_inner( - &mut self, - code_address: H160, - transfer: Transfer, - input: Bytes, - gas_limit: u64, - context: CallContext, - ) -> (Return, Gas, Bytes) { - let mut gas = Gas::new(gas_limit); + fn call_inner(&mut self, inputs: &CallInputs) -> (Return, Gas, Bytes) { + let mut gas = Gas::new(inputs.gas_limit); // Load account and get code. Account is now hot. - let (code, _) = self.code(code_address); + let (code, _) = self.code(inputs.contract); // check depth - if self.data.subroutine.depth() > machine::CALL_STACK_LIMIT { + if self.data.subroutine.depth() > interpreter::CALL_STACK_LIMIT { return (Return::CallTooDeep, gas, Bytes::new()); } // Create subroutine checkpoint let checkpoint = self.data.subroutine.create_checkpoint(); // touch address. For "EIP-158 State Clear" this will erase empty accounts. - if transfer.value.is_zero() { - self.load_account(context.address); + if inputs.transfer.value.is_zero() { + self.load_account(inputs.context.address); self.data .subroutine - .balance_add(context.address, U256::zero()); // touch the acc + .balance_add(inputs.context.address, U256::zero()); // touch the acc } // transfer value from caller to called account; match self.data.subroutine.transfer( - transfer.source, - transfer.target, - transfer.value, + inputs.transfer.source, + inputs.transfer.target, + inputs.transfer.value, self.data.db, ) { Err(e) => { @@ -444,10 +446,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } // call precompiles - if let Some(precompile) = self.precompiles.get(&code_address) { + if let Some(precompile) = self.precompiles.get(&inputs.contract) { let out = match precompile { - Precompile::Standard(fun) => fun(input.as_ref(), gas_limit), - Precompile::Custom(fun) => fun(input.as_ref(), gas_limit), + Precompile::Standard(fun) => fun(inputs.input.as_ref(), inputs.gas_limit), + Precompile::Custom(fun) => fun(inputs.input.as_ref(), inputs.gas_limit), }; match out { Ok(PrecompileOutput { output, cost, logs }) => { @@ -472,22 +474,23 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } } else { - // create machine and execute subcall - let contract = Contract::new_with_context::(input, code, &context); - let mut machine = - Machine::new::(contract, gas_limit, self.data.subroutine.depth()); + // create interp and execute subcall + let contract = + Contract::new_with_context::(inputs.input.clone(), code, &inputs.context); + let mut interp = + Interpreter::new::(contract, inputs.gas_limit, self.data.subroutine.depth()); if Self::INSPECT { self.inspector - .initialize_machine(&mut machine, &mut self.data, false); // TODO fix is_static + .initialize_interp(&mut interp, &mut self.data, false); // TODO fix is_static } - let exit_reason = machine.run::(self); + let exit_reason = interp.run::(self); if matches!(exit_reason, return_ok!()) { self.data.subroutine.checkpoint_commit(); } else { self.data.subroutine.checkpoint_revert(checkpoint); } - (exit_reason, machine.gas, machine.return_value()) + (exit_reason, interp.gas, interp.return_value()) } } } @@ -498,12 +501,13 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host const INSPECT: bool = INSPECT; type DB = DB; - fn step(&mut self, machine: &mut Machine, is_static: bool) -> Return { - self.inspector.step(machine, &mut self.data, is_static) + fn step(&mut self, interp: &mut Interpreter, is_static: bool) -> Return { + self.inspector.step(interp, &mut self.data, is_static) } - fn step_end(&mut self, ret: Return, machine: &mut Machine) -> Return { - self.inspector.step_end(ret, machine) + fn step_end(&mut self, interp: &mut Interpreter, is_static: bool, ret: Return) -> Return { + self.inspector + .step_end(interp, &mut self.data, is_static, ret) } fn env(&mut self) -> &mut Env { @@ -576,101 +580,69 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .selfdestruct(address, target, self.data.db) } - fn create( - &mut self, - caller: H160, - scheme: CreateScheme, - value: U256, - init_code: Bytes, - gas_limit: u64, - ) -> (Return, Option, Gas, Bytes) { + fn create(&mut self, inputs: &CreateInputs) -> (Return, Option, Gas, Bytes) { if INSPECT { - let (ret, address, gas, out) = self.inspector.create( - &mut self.data, - caller, - &scheme, - value, - &init_code, - gas_limit, - ); + let (ret, address, gas, out) = self.inspector.create(&mut self.data, inputs); if ret != Return::Continue { return (ret, address, gas, out); } } - let (ret, address, gas, out) = - self.create_inner::(caller, scheme, value, init_code.clone(), gas_limit); + let (ret, address, gas, out) = self.create_inner::(inputs); if INSPECT { - self.inspector.create_end( - &mut self.data, - caller, - &scheme, - value, - &init_code, - ret, - address, - gas_limit, - gas.remaining(), - &out, - ); + self.inspector + .create_end(&mut self.data, inputs, ret, address, gas, &out); } (ret, address, gas, out) } - fn call( - &mut self, - code_address: H160, - transfer: Transfer, - input: Bytes, - gas_limit: u64, - context: CallContext, - ) -> (Return, Gas, Bytes) { + fn call(&mut self, inputs: &CallInputs) -> (Return, Gas, Bytes) { if INSPECT { - let (ret, gas, out) = self.inspector.call( - &mut self.data, - code_address, - &context, - &transfer, - &input, - gas_limit, - SPEC::IS_STATIC_CALL, - ); + let (ret, gas, out) = self + .inspector + .call(&mut self.data, inputs, SPEC::IS_STATIC_CALL); if ret != Return::Continue { return (ret, gas, out); } } - let (ret, gas, out) = self.call_inner::( - code_address, - transfer.clone(), - input.clone(), - gas_limit, - context.clone(), - ); + let (ret, gas, out) = self.call_inner::(inputs); if INSPECT { - self.inspector.call_end( - &mut self.data, - code_address, - &context, - &transfer, - &input, - gas_limit, - gas.remaining(), - ret, - &out, - SPEC::IS_STATIC_CALL, - ); + self.inspector + .call_end(&mut self.data, inputs, gas, ret, &out, SPEC::IS_STATIC_CALL); } (ret, gas, out) } } +pub fn create_address(caller: H160, nonce: u64) -> H160 { + let mut stream = rlp::RlpStream::new_list(2); + stream.append(&caller); + stream.append(&nonce); + let out = H256::from_slice(Keccak256::digest(&stream.out()).as_slice()); + let out = H160::from_slice(&out.as_bytes()[12..]); + out +} + +/// Get the create address from given scheme. +pub fn create2_address(caller: H160, code_hash: H256, salt: U256) -> H160 { + let mut temp: [u8; 32] = [0; 32]; + salt.to_big_endian(&mut temp); + + let mut hasher = Keccak256::new(); + hasher.update(&[0xff]); + hasher.update(&caller[..]); + hasher.update(&temp); + hasher.update(&code_hash[..]); + H160::from_slice(&hasher.finalize().as_slice()[12..]) +} + /// EVM context host. pub trait Host { const INSPECT: bool; type DB: Database; - fn step(&mut self, machine: &mut Machine, is_static: bool) -> Return; - fn step_end(&mut self, ret: Return, machine: &mut Machine) -> Return; + fn step(&mut self, interp: &mut Interpreter, is_static: bool) -> Return; + fn step_end(&mut self, interp: &mut Interpreter, is_static: bool, ret: Return) -> Return; fn env(&mut self) -> &mut Env; @@ -693,22 +665,7 @@ pub trait Host { /// Mark an address to be deleted, with funds transferred to target. fn selfdestruct(&mut self, address: H160, target: H160) -> SelfDestructResult; /// Invoke a create operation. - fn create( - &mut self, - caller: H160, - scheme: CreateScheme, - value: U256, - init_code: Bytes, - gas: u64, - ) -> (Return, Option, Gas, Bytes); - + fn create(&mut self, inputs: &CreateInputs) -> (Return, Option, Gas, Bytes); /// Invoke a call operation. - fn call( - &mut self, - code_address: H160, - transfer: Transfer, - input: Bytes, - gas: u64, - context: CallContext, - ) -> (Return, Gas, Bytes); + fn call(&mut self, input: &CallInputs) -> (Return, Gas, Bytes); } diff --git a/crates/revm/src/gas.rs b/crates/revm/src/gas.rs new file mode 100644 index 0000000000..4b2271a13f --- /dev/null +++ b/crates/revm/src/gas.rs @@ -0,0 +1,101 @@ +mod calc; +mod constants; + +pub use calc::*; +pub use constants::*; + +use crate::{instructions::Return, return_ok, return_revert}; + +#[derive(Clone, Copy, Debug)] +pub struct Gas { + limit: u64, + used: u64, + memory: u64, + refunded: i64, + all_used_gas: u64, +} +impl Gas { + pub fn new(limit: u64) -> Self { + Self { + limit, + used: 0, + memory: 0, + refunded: 0, + all_used_gas: 0, + } + } + + pub fn reimburse_unspend(&mut self, exit: &Return, other: Gas) { + match *exit { + return_ok!() => { + self.erase_cost(other.remaining()); + self.record_refund(other.refunded()); + } + return_revert!() => { + self.erase_cost(other.remaining()); + } + _ => {} + } + } + + pub fn limit(&self) -> u64 { + self.limit + } + + pub fn memory(&self) -> u64 { + self.memory + } + + pub fn refunded(&self) -> i64 { + self.refunded + } + + pub fn spend(&self) -> u64 { + self.all_used_gas + } + + pub fn remaining(&self) -> u64 { + self.limit - self.all_used_gas + } + + pub fn erase_cost(&mut self, returned: u64) { + self.used -= returned; + self.all_used_gas -= returned; + } + + pub fn record_refund(&mut self, refund: i64) { + self.refunded += refund; + } + + /// Record an explict cost. + #[inline(always)] + pub fn record_cost(&mut self, cost: u64) -> bool { + let (all_used_gas, overflow) = self.all_used_gas.overflowing_add(cost); + if overflow || self.limit < all_used_gas { + return false; + } + + self.used += cost; + self.all_used_gas = all_used_gas; + true + } + + /// used in memory_resize! macro + + pub fn record_memory(&mut self, gas_memory: u64) -> bool { + if gas_memory > self.memory { + let (all_used_gas, overflow) = self.used.overflowing_add(gas_memory); + if overflow || self.limit < all_used_gas { + return false; + } + self.memory = gas_memory; + self.all_used_gas = all_used_gas; + } + true + } + + /// used in gas_refund! macro + pub fn gas_refund(&mut self, refund: i64) { + self.refunded += refund; + } +} diff --git a/crates/revm/src/instructions/gas/calc.rs b/crates/revm/src/gas/calc.rs similarity index 93% rename from crates/revm/src/instructions/gas/calc.rs rename to crates/revm/src/gas/calc.rs index 746442fb8d..b06fa53f9b 100644 --- a/crates/revm/src/instructions/gas/calc.rs +++ b/crates/revm/src/gas/calc.rs @@ -1,8 +1,5 @@ use super::constants::*; -use crate::{ - models::SelfDestructResult, - spec::{Spec, SpecId::*}, -}; +use crate::{models::SelfDestructResult, Spec, SpecId::*}; use primitive_types::U256; #[allow(clippy::collapsible_else_if)] @@ -66,6 +63,25 @@ pub fn create2_cost(len: usize) -> Option { Some(gas) } +fn log2floor(value: U256) -> u64 { + assert!(!value.is_zero()); + let mut l: u64 = 256; + for i in 0..4 { + let i = 3 - i; + if value.0[i] == 0u64 { + l -= 64; + } else { + l -= value.0[i].leading_zeros() as u64; + if l == 0 { + return l; + } else { + return l - 1; + } + } + } + l +} + pub fn exp_cost(power: U256) -> Option { if power.is_zero() { Some(EXP) @@ -75,9 +91,8 @@ pub fn exp_cost(power: U256) -> Option { } else { 10 }); // EIP-160: EXP cost increase - let gas = U256::from(EXP).checked_add( - gas_byte.checked_mul(U256::from(super::utils::log2floor(power) / 8 + 1))?, - )?; + let gas = U256::from(EXP) + .checked_add(gas_byte.checked_mul(U256::from(log2floor(power) / 8 + 1))?)?; if gas > U256::from(u64::MAX) { return None; diff --git a/crates/revm/src/instructions/gas/constants.rs b/crates/revm/src/gas/constants.rs similarity index 100% rename from crates/revm/src/instructions/gas/constants.rs rename to crates/revm/src/gas/constants.rs diff --git a/crates/revm/src/inspector.rs b/crates/revm/src/inspector.rs index 420bc2bbe8..71c05420c5 100644 --- a/crates/revm/src/inspector.rs +++ b/crates/revm/src/inspector.rs @@ -1,31 +1,29 @@ use bytes::Bytes; -use primitive_types::{H160, U256}; +use primitive_types::H160; -use crate::{ - evm_impl::EVMData, machine::Gas, CallContext, CreateScheme, Database, Machine, Return, Transfer, -}; +use crate::{evm_impl::EVMData, CallInputs, CreateInputs, Database, Gas, Interpreter, Return}; use auto_impl::auto_impl; #[auto_impl(&mut, Box)] pub trait Inspector { fn initialize(&mut self, _data: &mut EVMData<'_, DB>) {} - /// before machine get initialized this function is called. If returning something other them Return::Continue - /// we are skipping execution of machine. - fn initialize_machine( + /// before interp get initialized this function is called. If returning something other them Return::Continue + /// we are skipping execution of interp. + fn initialize_interp( &mut self, - _machine: &mut Machine, + _interp: &mut Interpreter, _data: &mut EVMData<'_, DB>, _is_static: bool, ) -> Return { Return::Continue } - /// get opcode by calling `machine.contract.opcode(machine.program_counter())`. - /// all other information can be obtained from machine. + /// get opcode by calling `interp.contract.opcode(interp.program_counter())`. + /// all other information can be obtained from interp. fn step( &mut self, - _machine: &mut Machine, + _interp: &mut Interpreter, _data: &mut EVMData<'_, DB>, _is_static: bool, ) -> Return { @@ -33,7 +31,13 @@ pub trait Inspector { } /// Called after `step` when instruction is executed. - fn step_end(&mut self, _eval: Return, _machine: &mut Machine) -> Return { + fn step_end( + &mut self, + _interp: &mut Interpreter, + _data: &mut EVMData<'_, DB>, + _is_static: bool, + _eval: Return, + ) -> Return { Return::Continue } @@ -44,11 +48,7 @@ pub trait Inspector { fn call( &mut self, _data: &mut EVMData<'_, DB>, - _call: H160, - _context: &CallContext, - _transfer: &Transfer, - _input: &Bytes, - _gas_limit: u64, + _inputs: &CallInputs, _is_static: bool, ) -> (Return, Gas, Bytes) { (Return::Continue, Gas::new(0), Bytes::new()) @@ -58,12 +58,8 @@ pub trait Inspector { fn call_end( &mut self, _data: &mut EVMData<'_, DB>, - _call: H160, - _context: &CallContext, - _transfer: &Transfer, - _input: &Bytes, - _gas_limit: u64, - _remaining_gas: u64, + _inputs: &CallInputs, + _remaining_gas: Gas, _ret: Return, _out: &Bytes, _is_static: bool, @@ -73,11 +69,7 @@ pub trait Inspector { fn create( &mut self, _data: &mut EVMData<'_, DB>, - _caller: H160, - _scheme: &CreateScheme, - _value: U256, - _init_code: &Bytes, - _gas_limit: u64, + _inputs: &CreateInputs, ) -> (Return, Option, Gas, Bytes) { (Return::Continue, None, Gas::new(0), Bytes::default()) } @@ -86,14 +78,10 @@ pub trait Inspector { fn create_end( &mut self, _data: &mut EVMData<'_, DB>, - _caller: H160, - _scheme: &CreateScheme, - _value: U256, - _init_code: &Bytes, + _inputs: &CreateInputs, _ret: Return, _address: Option, - _gas_limit: u64, - _remaining_gas: u64, + _remaining_gas: Gas, _out: &Bytes, ) { } diff --git a/crates/revm/src/instructions.rs b/crates/revm/src/instructions.rs new file mode 100644 index 0000000000..7753c74c58 --- /dev/null +++ b/crates/revm/src/instructions.rs @@ -0,0 +1,246 @@ +#[macro_use] +mod macros; +mod arithmetic; +mod bitwise; +mod control; +mod host; +mod host_env; +mod i256; +mod memory; +pub mod opcode; +mod stack; +mod system; + +pub use opcode::{OpCode, OPCODE_JUMPMAP}; + +use crate::{interpreter::Interpreter, CallScheme, Host, Spec, SpecId::*}; +use core::ops::{BitAnd, BitOr, BitXor}; +use primitive_types::U256; + +#[macro_export] +macro_rules! return_ok { + () => { + Return::Continue | Return::Stop | Return::Return | Return::SelfDestruct + }; +} + +#[macro_export] +macro_rules! return_revert { + () => { + Return::Revert | Return::CallTooDeep | Return::OutOfFund + }; +} + +#[repr(u8)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Return { + //success codes + Continue = 0x00, + Stop = 0x01, + Return = 0x02, + SelfDestruct = 0x03, + + // revert code + Revert = 0x20, // revert opcode + CallTooDeep = 0x21, + OutOfFund = 0x22, + + // error codes + OutOfGas = 0x50, + OpcodeNotFound, + CallNotAllowedInsideStatic, + InvalidOpcode, + InvalidJump, + InvalidMemoryRange, + NotActivated, + StackUnderflow, + StackOverflow, + OutOfOffset, + FatalNotSupported, + GasMaxFeeGreaterThanPriorityFee, + GasPriceLessThenBasefee, + CallerGasLimitMoreThenBlock, + RejectCallerWithCode, //new eip included in london + LackOfFundForGasLimit, + CreateCollision, + OverflowPayment, + Precompile, + + /// Create init code exceeds limit (runtime). + CreateContractLimit, + /// Create contract that begins with EF + CreateContractWithEF, +} + +#[inline(always)] +pub fn eval(opcode: u8, interp: &mut Interpreter, host: &mut H) -> Return { + match opcode { + /*12_u8..=15_u8 => Return::OpcodeNotFound, + 30_u8..=31_u8 => Return::OpcodeNotFound, + 33_u8..=47_u8 => Return::OpcodeNotFound, + 73_u8..=79_u8 => Return::OpcodeNotFound, + 92_u8..=95_u8 => Return::OpcodeNotFound, + 165_u8..=239_u8 => Return::OpcodeNotFound, + 246_u8..=249_u8 => Return::OpcodeNotFound, + 251_u8..=252_u8 => Return::OpcodeNotFound,*/ + opcode::STOP => Return::Stop, + opcode::ADD => op2_u256_tuple!(interp, overflowing_add), + opcode::MUL => op2_u256_tuple!(interp, overflowing_mul), + opcode::SUB => op2_u256_tuple!(interp, overflowing_sub), + opcode::DIV => op2_u256_fn!(interp, arithmetic::div), + opcode::SDIV => op2_u256_fn!(interp, arithmetic::sdiv), + opcode::MOD => op2_u256_fn!(interp, arithmetic::rem), + opcode::SMOD => op2_u256_fn!(interp, arithmetic::smod), + opcode::ADDMOD => op3_u256_fn!(interp, arithmetic::addmod), + opcode::MULMOD => op3_u256_fn!(interp, arithmetic::mulmod), + opcode::EXP => arithmetic::eval_exp::(interp), + opcode::SIGNEXTEND => op2_u256_fn!(interp, arithmetic::signextend), + opcode::LT => op2_u256_bool_ref!(interp, lt), + opcode::GT => op2_u256_bool_ref!(interp, gt), + opcode::SLT => op2_u256_fn!(interp, bitwise::slt), + opcode::SGT => op2_u256_fn!(interp, bitwise::sgt), + opcode::EQ => op2_u256_bool_ref!(interp, eq), + opcode::ISZERO => op1_u256_fn!(interp, bitwise::iszero), + opcode::AND => op2_u256!(interp, bitand), + opcode::OR => op2_u256!(interp, bitor), + opcode::XOR => op2_u256!(interp, bitxor), + opcode::NOT => op1_u256_fn!(interp, bitwise::not), + opcode::BYTE => op2_u256_fn!(interp, bitwise::byte), + opcode::SHL => op2_u256_fn!( + interp, + bitwise::shl, + S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM + ), + opcode::SHR => op2_u256_fn!( + interp, + bitwise::shr, + S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM + ), + opcode::SAR => op2_u256_fn!( + interp, + bitwise::sar, + S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM + ), + opcode::SHA3 => system::sha3(interp), + + opcode::ADDRESS => system::address(interp), + opcode::BALANCE => host::balance::(interp, host), + opcode::SELFBALANCE => host::selfbalance::(interp, host), + opcode::CODESIZE => system::codesize(interp), + opcode::CODECOPY => system::codecopy(interp), + opcode::CALLDATALOAD => system::calldataload(interp), + opcode::CALLDATASIZE => system::calldatasize(interp), + opcode::CALLDATACOPY => system::calldatacopy(interp), + opcode::POP => stack::pop(interp), + opcode::MLOAD => memory::mload(interp), + opcode::MSTORE => memory::mstore(interp), + opcode::MSTORE8 => memory::mstore8(interp), + opcode::JUMP => control::jump(interp), + opcode::JUMPI => control::jumpi(interp), + opcode::PC => control::pc(interp), + opcode::MSIZE => memory::msize(interp), + opcode::JUMPDEST => control::jumpdest(interp), + opcode::PUSH1 => stack::push::<1>(interp), + opcode::PUSH2 => stack::push::<2>(interp), + opcode::PUSH3 => stack::push::<3>(interp), + opcode::PUSH4 => stack::push::<4>(interp), + opcode::PUSH5 => stack::push::<5>(interp), + opcode::PUSH6 => stack::push::<6>(interp), + opcode::PUSH7 => stack::push::<7>(interp), + opcode::PUSH8 => stack::push::<8>(interp), + opcode::PUSH9 => stack::push::<9>(interp), + opcode::PUSH10 => stack::push::<10>(interp), + opcode::PUSH11 => stack::push::<11>(interp), + opcode::PUSH12 => stack::push::<12>(interp), + opcode::PUSH13 => stack::push::<13>(interp), + opcode::PUSH14 => stack::push::<14>(interp), + opcode::PUSH15 => stack::push::<15>(interp), + opcode::PUSH16 => stack::push::<16>(interp), + opcode::PUSH17 => stack::push::<17>(interp), + opcode::PUSH18 => stack::push::<18>(interp), + opcode::PUSH19 => stack::push::<19>(interp), + opcode::PUSH20 => stack::push::<20>(interp), + opcode::PUSH21 => stack::push::<21>(interp), + opcode::PUSH22 => stack::push::<22>(interp), + opcode::PUSH23 => stack::push::<23>(interp), + opcode::PUSH24 => stack::push::<24>(interp), + opcode::PUSH25 => stack::push::<25>(interp), + opcode::PUSH26 => stack::push::<26>(interp), + opcode::PUSH27 => stack::push::<27>(interp), + opcode::PUSH28 => stack::push::<28>(interp), + opcode::PUSH29 => stack::push::<29>(interp), + opcode::PUSH30 => stack::push::<30>(interp), + opcode::PUSH31 => stack::push::<31>(interp), + opcode::PUSH32 => stack::push::<32>(interp), + opcode::DUP1 => stack::dup::<1>(interp), + opcode::DUP2 => stack::dup::<2>(interp), + opcode::DUP3 => stack::dup::<3>(interp), + opcode::DUP4 => stack::dup::<4>(interp), + opcode::DUP5 => stack::dup::<5>(interp), + opcode::DUP6 => stack::dup::<6>(interp), + opcode::DUP7 => stack::dup::<7>(interp), + opcode::DUP8 => stack::dup::<8>(interp), + opcode::DUP9 => stack::dup::<9>(interp), + opcode::DUP10 => stack::dup::<10>(interp), + opcode::DUP11 => stack::dup::<11>(interp), + opcode::DUP12 => stack::dup::<12>(interp), + opcode::DUP13 => stack::dup::<13>(interp), + opcode::DUP14 => stack::dup::<14>(interp), + opcode::DUP15 => stack::dup::<15>(interp), + opcode::DUP16 => stack::dup::<16>(interp), + + opcode::SWAP1 => stack::swap::<1>(interp), + opcode::SWAP2 => stack::swap::<2>(interp), + opcode::SWAP3 => stack::swap::<3>(interp), + opcode::SWAP4 => stack::swap::<4>(interp), + opcode::SWAP5 => stack::swap::<5>(interp), + opcode::SWAP6 => stack::swap::<6>(interp), + opcode::SWAP7 => stack::swap::<7>(interp), + opcode::SWAP8 => stack::swap::<8>(interp), + opcode::SWAP9 => stack::swap::<9>(interp), + opcode::SWAP10 => stack::swap::<10>(interp), + opcode::SWAP11 => stack::swap::<11>(interp), + opcode::SWAP12 => stack::swap::<12>(interp), + opcode::SWAP13 => stack::swap::<13>(interp), + opcode::SWAP14 => stack::swap::<14>(interp), + opcode::SWAP15 => stack::swap::<15>(interp), + opcode::SWAP16 => stack::swap::<16>(interp), + + opcode::RETURN => control::ret(interp), + opcode::REVERT => control::revert::(interp), + opcode::INVALID => Return::InvalidOpcode, + opcode::BASEFEE => host_env::basefee::(interp, host), + opcode::ORIGIN => host_env::origin(interp, host), + opcode::CALLER => system::caller(interp), + opcode::CALLVALUE => system::callvalue(interp), + opcode::GASPRICE => host_env::gasprice(interp, host), + opcode::EXTCODESIZE => host::extcodesize::(interp, host), + opcode::EXTCODEHASH => host::extcodehash::(interp, host), + opcode::EXTCODECOPY => host::extcodecopy::(interp, host), + opcode::RETURNDATASIZE => system::returndatasize::(interp), + opcode::RETURNDATACOPY => system::returndatacopy::(interp), + opcode::BLOCKHASH => host::blockhash(interp, host), + opcode::COINBASE => host_env::coinbase(interp, host), + opcode::TIMESTAMP => host_env::timestamp(interp, host), + opcode::NUMBER => host_env::number(interp, host), + opcode::DIFFICULTY => host_env::difficulty(interp, host), + opcode::GASLIMIT => host_env::gaslimit(interp, host), + opcode::SLOAD => host::sload::(interp, host), + opcode::SSTORE => host::sstore::(interp, host), + opcode::GAS => system::gas(interp), + opcode::LOG0 => host::log::(interp, 0, host), + opcode::LOG1 => host::log::(interp, 1, host), + opcode::LOG2 => host::log::(interp, 2, host), + opcode::LOG3 => host::log::(interp, 3, host), + opcode::LOG4 => host::log::(interp, 4, host), + opcode::SELFDESTRUCT => host::selfdestruct::(interp, host), + opcode::CREATE => host::create::(interp, false, host), //check + opcode::CREATE2 => host::create::(interp, true, host), //check + opcode::CALL => host::call::(interp, CallScheme::Call, host), //check + opcode::CALLCODE => host::call::(interp, CallScheme::CallCode, host), //check + opcode::DELEGATECALL => host::call::(interp, CallScheme::DelegateCall, host), //check + opcode::STATICCALL => host::call::(interp, CallScheme::StaticCall, host), //check + opcode::CHAINID => host_env::chainid::(interp, host), + _ => Return::OpcodeNotFound, + } +} diff --git a/crates/revm/src/instructions/arithmetic.rs b/crates/revm/src/instructions/arithmetic.rs index 1982048186..6c7dacd439 100644 --- a/crates/revm/src/instructions/arithmetic.rs +++ b/crates/revm/src/instructions/arithmetic.rs @@ -1,4 +1,4 @@ -use crate::{instructions::gas, Machine, Return, Spec}; +use crate::{gas, Interpreter, Return, Spec}; use super::i256::{i256_div, i256_mod}; use core::{convert::TryInto, ops::Rem}; @@ -74,11 +74,11 @@ pub fn exp(op1: U256, op2: U256) -> U256 { r } -pub fn eval_exp(machine: &mut Machine) -> Return { - pop!(machine, op1, op2); - gas_or_fail!(machine, gas::exp_cost::(op2)); +pub fn eval_exp(interp: &mut Interpreter) -> Return { + pop!(interp, op1, op2); + gas_or_fail!(interp, gas::exp_cost::(op2)); let ret = exp(op1, op2); - push!(machine, ret); + push!(interp, ret); Return::Continue } diff --git a/crates/revm/src/instructions/control.rs b/crates/revm/src/instructions/control.rs new file mode 100644 index 0000000000..e057d41fd5 --- /dev/null +++ b/crates/revm/src/instructions/control.rs @@ -0,0 +1,76 @@ +use crate::{gas, interpreter::Interpreter, Return, Spec, SpecId::*}; +use primitive_types::U256; + +pub fn jump(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::MID); + pop!(interp, dest); + let dest = as_usize_or_fail!(dest, Return::InvalidJump); + if interp.contract.is_valid_jump(dest) { + // Safety: In analazis we are checking create our jump table and we do check above to be + // sure that jump is safe to execute. + interp.program_counter = unsafe { interp.contract.code.as_ptr().add(dest) }; + Return::Continue + } else { + Return::InvalidJump + } +} + +pub fn jumpi(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::HIGH); + pop!(interp, dest, value); + if !value.is_zero() { + let dest = as_usize_or_fail!(dest, Return::InvalidJump); + if interp.contract.is_valid_jump(dest) { + // Safety: In analazis we are checking if jump is valid destination and this if. + // make this unsafe block safe. + interp.program_counter = unsafe { interp.contract.code.as_ptr().add(dest) }; + Return::Continue + } else { + Return::InvalidJump + } + } else { + // if we are not doing jump, add next gas block. + interp.add_next_gas_block(interp.program_counter() - 1) + } +} + +pub fn jumpdest(interp: &mut Interpreter) -> Return { + gas!(interp, gas::JUMPDEST); + interp.add_next_gas_block(interp.program_counter() - 1) +} + +pub fn pc(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + push!(interp, U256::from(interp.program_counter() - 1)); + Return::Continue +} + +pub fn ret(interp: &mut Interpreter) -> Return { + // zero gas cost gas!(interp,gas::ZERO); + pop!(interp, start, len); + let len = as_usize_or_fail!(len, Return::OutOfGas); + if len == 0 { + interp.return_range = usize::MAX..usize::MAX; + } else { + let offset = as_usize_or_fail!(start, Return::OutOfGas); + memory_resize!(interp, offset, len); + interp.return_range = offset..(offset + len); + } + Return::Return +} + +pub fn revert(interp: &mut Interpreter) -> Return { + // zero gas cost gas!(interp,gas::ZERO); + // EIP-140: REVERT instruction + check!(SPEC::enabled(BYZANTINE)); + pop!(interp, start, len); + let len = as_usize_or_fail!(len, Return::OutOfGas); + if len == 0 { + interp.return_range = usize::MAX..usize::MAX; + } else { + let offset = as_usize_or_fail!(start, Return::OutOfGas); + memory_resize!(interp, offset, len); + interp.return_range = offset..(offset + len); + } + Return::Revert +} diff --git a/crates/revm/src/instructions/gas/mod.rs b/crates/revm/src/instructions/gas/mod.rs deleted file mode 100644 index d88a46afd0..0000000000 --- a/crates/revm/src/instructions/gas/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//#![deny(warnings)] -#![forbid(unsafe_code, unused_variables)] -//#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; -mod calc; -mod constants; -mod utils; - -pub use calc::*; -pub use constants::*; diff --git a/crates/revm/src/instructions/gas/utils.rs b/crates/revm/src/instructions/gas/utils.rs deleted file mode 100644 index 8239143ac4..0000000000 --- a/crates/revm/src/instructions/gas/utils.rs +++ /dev/null @@ -1,20 +0,0 @@ -use primitive_types::U256; - -pub fn log2floor(value: U256) -> u64 { - assert!(!value.is_zero()); - let mut l: u64 = 256; - for i in 0..4 { - let i = 3 - i; - if value.0[i] == 0u64 { - l -= 64; - } else { - l -= value.0[i].leading_zeros() as u64; - if l == 0 { - return l; - } else { - return l - 1; - } - } - } - l -} diff --git a/crates/revm/src/instructions/host.rs b/crates/revm/src/instructions/host.rs new file mode 100644 index 0000000000..70b517b25c --- /dev/null +++ b/crates/revm/src/instructions/host.rs @@ -0,0 +1,393 @@ +use crate::{alloc::vec::Vec, SpecId::*}; +use crate::{ + gas, interpreter::Interpreter, return_ok, return_revert, CallContext, CallScheme, CreateScheme, + Host, Return, Spec, Transfer, +}; +use crate::{CallInputs, CreateInputs}; +use bytes::Bytes; +use core::cmp::min; +use primitive_types::{H160, H256, U256}; + +pub fn balance(interp: &mut Interpreter, host: &mut H) -> Return { + pop_address!(interp, address); + let (balance, is_cold) = host.balance(address); + gas!( + interp, + if SPEC::enabled(ISTANBUL) { + // EIP-1884: Repricing for trie-size-dependent opcodes + gas::account_access_gas::(is_cold) + } else if SPEC::enabled(TANGERINE) { + 400 + } else { + 20 + } + ); + push!(interp, balance); + + Return::Continue +} + +pub fn selfbalance(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::LOW); + // EIP-1884: Repricing for trie-size-dependent opcodes + check!(SPEC::enabled(ISTANBUL)); + + let (balance, _) = host.balance(interp.contract.address); + push!(interp, balance); + + Return::Continue +} + +pub fn extcodesize(interp: &mut Interpreter, host: &mut H) -> Return { + pop_address!(interp, address); + + let (code, is_cold) = host.code(address); + gas!(interp, gas::account_access_gas::(is_cold)); + + push!(interp, U256::from(code.len())); + + Return::Continue +} + +pub fn extcodehash(interp: &mut Interpreter, host: &mut H) -> Return { + check!(SPEC::enabled(CONSTANTINOPLE)); // EIP-1052: EXTCODEHASH opcode + pop_address!(interp, address); + let (code_hash, is_cold) = host.code_hash(address); + gas!( + interp, + if SPEC::enabled(ISTANBUL) { + // EIP-1884: Repricing for trie-size-dependent opcodes + gas::account_access_gas::(is_cold) + } else { + 400 + } + ); + push_h256!(interp, code_hash); + + Return::Continue +} + +pub fn extcodecopy(interp: &mut Interpreter, host: &mut H) -> Return { + pop_address!(interp, address); + pop!(interp, memory_offset, code_offset, len_u256); + + let (code, is_cold) = host.code(address); + gas_or_fail!(interp, gas::extcodecopy_cost::(len_u256, is_cold)); + let len = as_usize_or_fail!(len_u256, Return::OutOfGas); + if len == 0 { + return Return::Continue; + } + let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); + let code_offset = min(as_usize_saturated!(code_offset), code.len()); + memory_resize!(interp, memory_offset, len); + + // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it + interp + .memory + .set_data(memory_offset, code_offset, len, &code); + Return::Continue +} + +pub fn blockhash(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BLOCKHASH); + + pop!(interp, number); + push_h256!(interp, host.block_hash(number)); + + Return::Continue +} + +pub fn sload(interp: &mut Interpreter, host: &mut H) -> Return { + pop!(interp, index); + let (value, is_cold) = host.sload(interp.contract.address, index); + gas!(interp, gas::sload_cost::(is_cold)); + push!(interp, value); + Return::Continue +} + +pub fn sstore(interp: &mut Interpreter, host: &mut H) -> Return { + check!(!SPEC::IS_STATIC_CALL); + + pop!(interp, index, value); + let (original, old, new, is_cold) = host.sstore(interp.contract.address, index, value); + gas_or_fail!(interp, { + let remaining_gas = interp.gas.remaining(); + gas::sstore_cost::(original, old, new, remaining_gas, is_cold) + }); + refund!(interp, gas::sstore_refund::(original, old, new)); + Return::Continue +} + +pub fn log(interp: &mut Interpreter, n: u8, host: &mut H) -> Return { + check!(!SPEC::IS_STATIC_CALL); + + pop!(interp, offset, len); + gas_or_fail!(interp, gas::log_cost(n, len)); + let len = as_usize_or_fail!(len, Return::OutOfGas); + let data = if len == 0 { + Bytes::new() + } else { + let offset = as_usize_or_fail!(offset, Return::OutOfGas); + memory_resize!(interp, offset, len); + Bytes::copy_from_slice(interp.memory.get_slice(offset, len)) + }; + let n = n as usize; + if interp.stack.len() < n { + return Return::StackUnderflow; + } + + let mut topics = Vec::with_capacity(n); + for _ in 0..(n) { + let mut t = H256::zero(); + // Sefety: stack bounds already checked few lines above + unsafe { interp.stack.pop_unsafe().to_big_endian(t.as_bytes_mut()) }; + topics.push(t); + } + + host.log(interp.contract.address, topics, data); + Return::Continue +} + +pub fn selfdestruct(interp: &mut Interpreter, host: &mut H) -> Return { + check!(!SPEC::IS_STATIC_CALL); + pop_address!(interp, target); + + let res = host.selfdestruct(interp.contract.address, target); + + // EIP-3529: Reduction in refunds + if !SPEC::enabled(LONDON) && !res.previously_destroyed { + refund!(interp, gas::SELFDESTRUCT) + } + gas!(interp, gas::selfdestruct_cost::(res)); + + Return::SelfDestruct +} + +fn gas_call_l64_after(interp: &mut Interpreter) -> Result { + if SPEC::enabled(TANGERINE) { + //EIP-150: Gas cost changes for IO-heavy operations + let gas = interp.gas().remaining(); + Ok(gas - gas / 64) + } else { + Ok(interp.gas().remaining()) + } +} + +pub fn create( + interp: &mut Interpreter, + is_create2: bool, + host: &mut H, +) -> Return { + check!(!SPEC::IS_STATIC_CALL); + if is_create2 { + check!(SPEC::enabled(CONSTANTINOPLE)); // EIP-1014: Skinny CREATE2 + } + + interp.return_data_buffer = Bytes::new(); + + pop!(interp, value, code_offset, len); + let len = as_usize_or_fail!(len, Return::OutOfGas); + + let code = if len == 0 { + Bytes::new() + } else { + let code_offset = as_usize_or_fail!(code_offset, Return::OutOfGas); + memory_resize!(interp, code_offset, len); + Bytes::copy_from_slice(interp.memory.get_slice(code_offset, len)) + }; + + let scheme = if is_create2 { + pop!(interp, salt); + gas_or_fail!(interp, gas::create2_cost(len)); + CreateScheme::Create2 { salt } + } else { + gas!(interp, gas::CREATE); + CreateScheme::Create + }; + + // take remaining gas and deduce l64 part of it. + let gas_limit = try_or_fail!(gas_call_l64_after::(interp)); + gas!(interp, gas_limit); + + let create_input = CreateInputs { + caller: interp.contract.address, + scheme, + value, + init_code: code, + gas_limit, + }; + + let (reason, address, gas, return_data) = host.create::(&create_input); + interp.return_data_buffer = return_data; + let created_address: H256 = if matches!(reason, return_ok!()) { + address.map(|a| a.into()).unwrap_or_default() + } else { + H256::default() + }; + push_h256!(interp, created_address); + // reimburse gas that is not spend + interp.gas.reimburse_unspend(&reason, gas); + match reason { + Return::FatalNotSupported => Return::FatalNotSupported, + _ => interp.add_next_gas_block(interp.program_counter() - 1), + } +} + +pub fn call( + interp: &mut Interpreter, + scheme: CallScheme, + host: &mut H, +) -> Return { + match scheme { + CallScheme::DelegateCall => check!(SPEC::enabled(HOMESTEAD)), // EIP-7: DELEGATECALL + CallScheme::StaticCall => check!(SPEC::enabled(BYZANTINE)), // EIP-214: New opcode STATICCALL + _ => (), + } + interp.return_data_buffer = Bytes::new(); + + pop!(interp, local_gas_limit); + pop_address!(interp, to); + let local_gas_limit = if local_gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + local_gas_limit.as_u64() + }; + + let value = match scheme { + CallScheme::CallCode => { + pop!(interp, value); + value + } + CallScheme::Call => { + pop!(interp, value); + if SPEC::IS_STATIC_CALL && !value.is_zero() { + return Return::CallNotAllowedInsideStatic; + } + value + } + CallScheme::DelegateCall | CallScheme::StaticCall => U256::zero(), + }; + + pop!(interp, in_offset, in_len, out_offset, out_len); + + let in_len = as_usize_or_fail!(in_len, Return::OutOfGas); + let input = if in_len != 0 { + let in_offset = as_usize_or_fail!(in_offset, Return::OutOfGas); + memory_resize!(interp, in_offset, in_len); + Bytes::copy_from_slice(interp.memory.get_slice(in_offset, in_len)) + } else { + Bytes::new() + }; + + let out_len = as_usize_or_fail!(out_len, Return::OutOfGas); + let out_offset = if out_len != 0 { + let out_offset = as_usize_or_fail!(out_offset, Return::OutOfGas); + memory_resize!(interp, out_offset, out_len); + out_offset + } else { + usize::MAX //unrealistic value so we are sure it is not used + }; + + let context = match scheme { + CallScheme::Call | CallScheme::StaticCall => CallContext { + address: to, + caller: interp.contract.address, + apparent_value: value, + }, + CallScheme::CallCode => CallContext { + address: interp.contract.address, + caller: interp.contract.address, + apparent_value: value, + }, + CallScheme::DelegateCall => CallContext { + address: interp.contract.address, + caller: interp.contract.caller, + apparent_value: interp.contract.value, + }, + }; + + let transfer = if scheme == CallScheme::Call { + Transfer { + source: interp.contract.address, + target: to, + value, + } + } else if scheme == CallScheme::CallCode { + Transfer { + source: interp.contract.address, + target: interp.contract.address, + value, + } + } else { + //this is dummy send for StaticCall and DelegateCall, it should do nothing and dont touch anything. + Transfer { + source: interp.contract.address, + target: interp.contract.address, + value: U256::zero(), + } + }; + + // load account and calculate gas cost. + let (is_cold, exist) = host.load_account(to); + let is_new = !exist; + //let is_cold = false; + gas!( + interp, + gas::call_cost::( + value, + is_new, + is_cold, + matches!(scheme, CallScheme::Call | CallScheme::CallCode), + matches!(scheme, CallScheme::Call | CallScheme::StaticCall), + ) + ); + + // take l64 part of gas_limit + let global_gas_limit = try_or_fail!(gas_call_l64_after::(interp)); + let mut gas_limit = min(global_gas_limit, local_gas_limit); + + gas!(interp, gas_limit); + + // add call stipend if there is value to be transfered. + if matches!(scheme, CallScheme::Call | CallScheme::CallCode) && !transfer.value.is_zero() { + gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); + } + let is_static = matches!(scheme, CallScheme::StaticCall); + + let call_input = CallInputs { + contract: to, + transfer, + input, + gas_limit, + context, + }; + // CALL CONTRACT, with static or ordinary spec. + let (reason, gas, return_data) = if is_static { + host.call::(&call_input) + } else { + host.call::(&call_input) + }; + interp.return_data_buffer = return_data; + + let target_len = min(out_len, interp.return_data_buffer.len()); + // return unspend gas. + interp.gas.reimburse_unspend(&reason, gas); + match reason { + return_ok!() => { + interp + .memory + .set(out_offset, &interp.return_data_buffer[..target_len]); + push!(interp, U256::one()); + } + return_revert!() => { + push!(interp, U256::zero()); + interp + .memory + .set(out_offset, &interp.return_data_buffer[..target_len]); + } + _ => { + push!(interp, U256::zero()); + } + } + interp.add_next_gas_block(interp.program_counter() - 1) +} diff --git a/crates/revm/src/instructions/host_env.rs b/crates/revm/src/instructions/host_env.rs new file mode 100644 index 0000000000..b016f56dde --- /dev/null +++ b/crates/revm/src/instructions/host_env.rs @@ -0,0 +1,61 @@ +use crate::{interpreter::Interpreter, Host, Return, Spec, SpecId::*}; +use primitive_types::H256; + +pub fn chainid(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + // EIP-1344: ChainID opcode + check!(SPEC::enabled(ISTANBUL)); + push!(interp, host.env().cfg.chain_id); + Return::Continue +} + +pub fn coinbase(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push_h256!(interp, host.env().block.coinbase.into()); + Return::Continue +} + +pub fn timestamp(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push!(interp, host.env().block.timestamp); + Return::Continue +} + +pub fn number(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push!(interp, host.env().block.number); + Return::Continue +} + +pub fn difficulty(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push!(interp, host.env().block.difficulty); + Return::Continue +} + +pub fn gaslimit(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push!(interp, host.env().block.gas_limit); + Return::Continue +} + +pub fn gasprice(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + push!(interp, host.env().effective_gas_price()); + Return::Continue +} + +pub fn basefee(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + // EIP-3198: BASEFEE opcode + check!(SPEC::enabled(LONDON)); + push!(interp, host.env().block.basefee); + Return::Continue +} + +pub fn origin(interp: &mut Interpreter, host: &mut H) -> Return { + // gas!(interp, gas::BASE); + let ret = H256::from(host.env().tx.caller); + push_h256!(interp, ret); + Return::Continue +} diff --git a/crates/revm/src/instructions/i256.rs b/crates/revm/src/instructions/i256.rs index 7cb795dfa5..45ef39960b 100644 --- a/crates/revm/src/instructions/i256.rs +++ b/crates/revm/src/instructions/i256.rs @@ -73,6 +73,61 @@ pub fn i256_cmp(mut first: U256, mut second: U256) -> Ordering { (Sign::Plus, Sign::Plus) => first.cmp(&second), } } + +#[inline(always)] +pub fn i256_div(mut first: U256, mut second: U256) -> U256 { + let second_sign = i256_sign::(&mut second); + if second_sign == Sign::Zero { + return U256::zero(); + } + let first_sign = i256_sign::(&mut first); + if first_sign == Sign::Minus && first == MIN_NEGATIVE_VALUE && second == U256::one() { + return two_compl(MIN_NEGATIVE_VALUE); + } + + //let mut d = first / second; + let mut d = div_u256::div_mod(first, second).0; + + u256_remove_sign(&mut d); + //set sign bit to zero + + if d.is_zero() { + return U256::zero(); + } + + match (first_sign, second_sign) { + (Sign::Zero, Sign::Plus) + | (Sign::Plus, Sign::Zero) + | (Sign::Zero, Sign::Zero) + | (Sign::Plus, Sign::Plus) + | (Sign::Minus, Sign::Minus) => d, + (Sign::Zero, Sign::Minus) + | (Sign::Plus, Sign::Minus) + | (Sign::Minus, Sign::Zero) + | (Sign::Minus, Sign::Plus) => two_compl(d), + } +} + +#[inline(always)] +pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { + let first_sign = i256_sign::(&mut first); + if first_sign == Sign::Zero { + return U256::zero(); + } + + let _ = i256_sign::(&mut second); + let mut r = first % second; + u256_remove_sign(&mut r); + if r.is_zero() { + return U256::zero(); + } + if first_sign == Sign::Minus { + two_compl(r) + } else { + r + } +} + pub mod div_u256 { use super::*; @@ -334,68 +389,6 @@ pub mod div_u256 { } } -#[inline(always)] -pub fn i256_div(mut first: U256, mut second: U256) -> U256 { - let second_sign = i256_sign::(&mut second); - if second_sign == Sign::Zero { - return U256::zero(); - } - let first_sign = i256_sign::(&mut first); - if first_sign == Sign::Minus && first == MIN_NEGATIVE_VALUE && second == U256::one() { - return two_compl(MIN_NEGATIVE_VALUE); - } - - //use crypto_bigint::U256 as fastU256; - // let ff = fastU256::from(first.0); - //let sf = fastU256::from(second.0); - - //let d = ff.checked_div(&sf).unwrap(); - //let mut d: U256 = U256(d.to_uint_array()); - - //let mut d = first/second; - let mut d = div_u256::div_mod(first, second).0; - //let mut d = U256(inner_zkp_u256::div_rem(&first.0, &second.0)); - - u256_remove_sign(&mut d); - //set sign bit to zero - - if d.is_zero() { - return U256::zero(); - } - - match (first_sign, second_sign) { - (Sign::Zero, Sign::Plus) - | (Sign::Plus, Sign::Zero) - | (Sign::Zero, Sign::Zero) - | (Sign::Plus, Sign::Plus) - | (Sign::Minus, Sign::Minus) => d, - (Sign::Zero, Sign::Minus) - | (Sign::Plus, Sign::Minus) - | (Sign::Minus, Sign::Zero) - | (Sign::Minus, Sign::Plus) => two_compl(d), - } -} - -#[inline(always)] -pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { - let first_sign = i256_sign::(&mut first); - if first_sign == Sign::Zero { - return U256::zero(); - } - - let _ = i256_sign::(&mut second); - let mut r = first % second; - u256_remove_sign(&mut r); - if r.is_zero() { - return U256::zero(); - } - if first_sign == Sign::Minus { - two_compl(r) - } else { - r - } -} - #[cfg(test)] mod tests { use super::*; @@ -428,19 +421,4 @@ mod tests { assert_eq!(i256_div(one_hundred, minus_one), neg_one_hundred); assert_eq!(i256_div(one_hundred, two), fifty); } - - #[test] - fn benchmark_div() { - use super::*; - - let mut f = U256([1, 100, 1, 1]); - let mut s = U256([0, 0, 10, 0]); - - //let time = std::time::Instant::now(); - for i in 0..1_000_000 { - f.0[1] = i; - s.0[3] = div_u256::div_mod(f, s).0 .0[3]; - } - //println!("TIME:{:?}", time.elapsed()); - } } diff --git a/crates/revm/src/instructions/macros.rs b/crates/revm/src/instructions/macros.rs index c3591a8aa4..bf98036930 100644 --- a/crates/revm/src/instructions/macros.rs +++ b/crates/revm/src/instructions/macros.rs @@ -18,9 +18,9 @@ macro_rules! check { } macro_rules! gas { - ($machine:expr, $gas:expr) => { + ($interp:expr, $gas:expr) => { if crate::USE_GAS { - if !$machine.gas.record_cost(($gas)) { + if !$interp.gas.record_cost(($gas)) { return Return::OutOfGas; } } @@ -28,18 +28,18 @@ macro_rules! gas { } macro_rules! refund { - ($machine:expr, $gas:expr) => {{ + ($interp:expr, $gas:expr) => {{ if crate::USE_GAS { - $machine.gas.gas_refund($gas); + $interp.gas.gas_refund($gas); } }}; } macro_rules! gas_or_fail { - ($machine:expr, $gas:expr) => { + ($interp:expr, $gas:expr) => { if crate::USE_GAS { match $gas { - Some(gas_used) => gas!($machine, gas_used), + Some(gas_used) => gas!($interp, gas_used), None => return Return::OutOfGas, } } @@ -47,23 +47,20 @@ macro_rules! gas_or_fail { } macro_rules! memory_resize { - ($machine:expr, $offset:expr, $len:expr) => {{ + ($interp:expr, $offset:expr, $len:expr) => {{ let len: usize = $len; let offset: usize = $offset; if let Some(new_size) = - crate::machine::memory::next_multiple_of_32(offset.saturating_add(len)) + crate::interpreter::memory::next_multiple_of_32(offset.saturating_add(len)) { - if new_size > $machine.memory.len() { + if new_size > $interp.memory.len() { if crate::USE_GAS { let num_bytes = new_size / 32; - if !$machine - .gas - .record_memory(crate::instructions::gas::memory_gas(num_bytes)) - { + if !$interp.gas.record_memory(crate::gas::memory_gas(num_bytes)) { return Return::OutOfGas; } } - $machine.memory.resize(new_size); + $interp.memory.resize(new_size); } } else { return Return::OutOfGas; @@ -72,15 +69,15 @@ macro_rules! memory_resize { } macro_rules! pop_address { - ( $machine:expr, $x1:ident) => { - if $machine.stack.len() < 1 { + ( $interp:expr, $x1:ident) => { + if $interp.stack.len() < 1 { return Return::StackUnderflow; } let mut temp = H256::zero(); // Safety: Length is checked above. let $x1: H160 = { unsafe { - $machine + $interp .stack .pop_unsafe() .to_big_endian(temp.as_bytes_mut()) @@ -88,15 +85,15 @@ macro_rules! pop_address { temp.into() }; }; - ( $machine:expr, $x1:ident, $x2:ident) => { - if $machine.stack.len() < 2 { + ( $interp:expr, $x1:ident, $x2:ident) => { + if $interp.stack.len() < 2 { return Return::StackUnderflow; } let mut temp = H256::zero(); $x1: H160 = { // Safety: Length is checked above. unsafe { - $machine + $interp .stack .pop_unsafe() .to_big_endian(temp.as_bytes_mut()) @@ -107,7 +104,7 @@ macro_rules! pop_address { temp = H256::zero(); // Safety: Length is checked above. unsafe { - $machine + $interp .stack .pop_unsafe() .to_big_endian(temp.as_bytes_mut()) @@ -118,65 +115,65 @@ macro_rules! pop_address { } macro_rules! pop { - ( $machine:expr, $x1:ident) => { - if $machine.stack.len() < 1 { + ( $interp:expr, $x1:ident) => { + if $interp.stack.len() < 1 { return Return::StackUnderflow; } // Safety: Length is checked above. - let $x1 = unsafe { $machine.stack.pop_unsafe() }; + let $x1 = unsafe { $interp.stack.pop_unsafe() }; }; - ( $machine:expr, $x1:ident, $x2:ident) => { - if $machine.stack.len() < 2 { + ( $interp:expr, $x1:ident, $x2:ident) => { + if $interp.stack.len() < 2 { return Return::StackUnderflow; } // Safety: Length is checked above. - let ($x1, $x2) = unsafe { $machine.stack.pop2_unsafe() }; + let ($x1, $x2) = unsafe { $interp.stack.pop2_unsafe() }; }; - ( $machine:expr, $x1:ident, $x2:ident, $x3:ident) => { - if $machine.stack.len() < 3 { + ( $interp:expr, $x1:ident, $x2:ident, $x3:ident) => { + if $interp.stack.len() < 3 { return Return::StackUnderflow; } // Safety: Length is checked above. - let ($x1, $x2, $x3) = unsafe { $machine.stack.pop3_unsafe() }; + let ($x1, $x2, $x3) = unsafe { $interp.stack.pop3_unsafe() }; }; - ( $machine:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident) => { - if $machine.stack.len() < 4 { + ( $interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident) => { + if $interp.stack.len() < 4 { return Return::StackUnderflow; } // Safety: Length is checked above. - let ($x1, $x2, $x3, $x4) = unsafe { $machine.stack.pop4_unsafe() }; + let ($x1, $x2, $x3, $x4) = unsafe { $interp.stack.pop4_unsafe() }; }; } macro_rules! pop_top { - ( $machine:expr, $x1:ident) => { - if $machine.stack.len() < 1 { + ( $interp:expr, $x1:ident) => { + if $interp.stack.len() < 1 { return Return::StackUnderflow; } // Safety: Length is checked above. - let $x1 = unsafe { $machine.stack.top_unsafe() }; + let $x1 = unsafe { $interp.stack.top_unsafe() }; }; - ( $machine:expr, $x1:ident, $x2:ident) => { - if $machine.stack.len() < 2 { + ( $interp:expr, $x1:ident, $x2:ident) => { + if $interp.stack.len() < 2 { return Return::StackUnderflow; } // Safety: Length is checked above. - let ($x1, $x2) = unsafe { $machine.stack.pop_top_unsafe() }; + let ($x1, $x2) = unsafe { $interp.stack.pop_top_unsafe() }; }; - ( $machine:expr, $x1:ident, $x2:ident, $x3:ident) => { - if $machine.stack.len() < 3 { + ( $interp:expr, $x1:ident, $x2:ident, $x3:ident) => { + if $interp.stack.len() < 3 { return Return::StackUnderflow; } // Safety: Length is checked above. - let ($x1, $x2, $x3) = unsafe { $machine.stack.pop2_top_unsafe() }; + let ($x1, $x2, $x3) = unsafe { $interp.stack.pop2_top_unsafe() }; }; } macro_rules! push_h256 { - ( $machine:expr, $( $x:expr ),* ) => ( + ( $interp:expr, $( $x:expr ),* ) => ( $( - match $machine.stack.push_h256($x) { + match $interp.stack.push_h256($x) { Ok(()) => (), Err(e) => return e, } @@ -185,9 +182,9 @@ macro_rules! push_h256 { } macro_rules! push { - ( $machine:expr, $( $x:expr ),* ) => ( + ( $interp:expr, $( $x:expr ),* ) => ( $( - match $machine.stack.push($x) { + match $interp.stack.push($x) { Ok(()) => (), Err(e) => return e, } @@ -196,9 +193,9 @@ macro_rules! push { } macro_rules! op1_u256_fn { - ( $machine:expr, $op:path ) => {{ - //gas!($machine, $gas); - pop_top!($machine, op1); + ( $interp:expr, $op:path ) => {{ + // gas!($interp, $gas); + pop_top!($interp, op1); *op1 = $op(*op1); Return::Continue @@ -206,9 +203,9 @@ macro_rules! op1_u256_fn { } macro_rules! op2_u256_bool_ref { - ( $machine:expr, $op:ident) => {{ - //gas!($machine, $gas); - pop_top!($machine, op1, op2); + ( $interp:expr, $op:ident) => {{ + // gas!($interp, $gas); + pop_top!($interp, op1, op2); let ret = op1.$op(&op2); *op2 = if ret { U256::one() } else { U256::zero() }; @@ -217,26 +214,26 @@ macro_rules! op2_u256_bool_ref { } macro_rules! op2_u256 { - ( $machine:expr, $op:ident) => {{ - //gas!($machine, $gas); - pop_top!($machine, op1, op2); + ( $interp:expr, $op:ident) => {{ + // gas!($interp, $gas); + pop_top!($interp, op1, op2); *op2 = op1.$op(*op2); Return::Continue }}; } macro_rules! op2_u256_tuple { - ( $machine:expr, $op:ident) => {{ - //gas!($machine, $gas); + ( $interp:expr, $op:ident) => {{ + // gas!($interp, $gas); - pop_top!($machine, op1, op2); + pop_top!($interp, op1, op2); let (ret, ..) = op1.$op(*op2); *op2 = ret; Return::Continue }}; - ( $machine:expr, $op:ident ) => {{ - pop_top!($machine, op1, op2); + ( $interp:expr, $op:ident ) => {{ + pop_top!($interp, op1, op2); let (ret, ..) = op1.$op(op2); *op2 = ret; @@ -245,32 +242,32 @@ macro_rules! op2_u256_tuple { } macro_rules! op2_u256_fn { - ( $machine:expr, $op:path ) => {{ - //gas!($machine, $gas); + ( $interp:expr, $op:path ) => {{ + // gas!($interp, $gas); - pop_top!($machine, op1, op2); + pop_top!($interp, op1, op2); *op2 = $op(op1, *op2); Return::Continue }}; - ( $machine:expr, $op:path, $enabled:expr) => {{ + ( $interp:expr, $op:path, $enabled:expr) => {{ check!(($enabled)); - op2_u256_fn!($machine, $op) + op2_u256_fn!($interp, $op) }}; } macro_rules! op3_u256_fn { - ( $machine:expr, $op:path) => {{ - //gas!($machine, $gas); + ( $interp:expr, $op:path) => {{ + // gas!($interp, $gas); - pop_top!($machine, op1, op2, op3); + pop_top!($interp, op1, op2, op3); *op3 = $op(op1, op2, *op3); Return::Continue }}; - ( $machine:expr, $op:path, $spec:ident :: $enabled:ident) => {{ + ( $interp:expr, $op:path, $spec:ident :: $enabled:ident) => {{ check!($spec::$enabled); - op3_u256_fn!($machine, $op) + op3_u256_fn!($interp, $op) }}; } diff --git a/crates/revm/src/instructions/memory.rs b/crates/revm/src/instructions/memory.rs new file mode 100644 index 0000000000..486a5b9cb5 --- /dev/null +++ b/crates/revm/src/instructions/memory.rs @@ -0,0 +1,40 @@ +use crate::{interpreter::Interpreter, Return}; +use primitive_types::U256; + +pub fn mload(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + pop!(interp, index); + let index = as_usize_or_fail!(index, Return::OutOfGas); + memory_resize!(interp, index, 32); + push!( + interp, + U256::from_big_endian(interp.memory.get_slice(index, 32)) + ); + Return::Continue +} + +pub fn mstore(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + pop!(interp, index, value); + let index = as_usize_or_fail!(index, Return::OutOfGas); + memory_resize!(interp, index, 32); + interp.memory.set_u256(index, value); + Return::Continue +} + +pub fn mstore8(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + pop!(interp, index, value); + let index = as_usize_or_fail!(index, Return::OutOfGas); + memory_resize!(interp, index, 1); + let value = (value.low_u32() & 0xff) as u8; + // Safety: we resized our memory two lines above. + unsafe { interp.memory.set_byte(index, value) } + Return::Continue +} + +pub fn msize(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + push!(interp, U256::from(interp.memory.effective_len())); + Return::Continue +} diff --git a/crates/revm/src/instructions/misc.rs b/crates/revm/src/instructions/misc.rs deleted file mode 100644 index 087f551ca3..0000000000 --- a/crates/revm/src/instructions/misc.rs +++ /dev/null @@ -1,227 +0,0 @@ -use super::gas; -use crate::{machine::Machine, util, Return, Spec, SpecId::*}; -use primitive_types::{H256, U256}; - -pub fn codesize(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - let size = U256::from(machine.contract.code_size); - push!(machine, size); - Return::Continue -} - -pub fn codecopy(machine: &mut Machine) -> Return { - pop!(machine, memory_offset, code_offset, len); - gas_or_fail!(machine, gas::verylowcopy_cost(len)); - let len = as_usize_or_fail!(len, Return::OutOfGas); - if len == 0 { - return Return::Continue; - } - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); - let code_offset = as_usize_saturated!(code_offset); - memory_resize!(machine, memory_offset, len); - - // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - machine - .memory - .set_data(memory_offset, code_offset, len, &machine.contract.code); - - Return::Continue -} - -pub fn calldataload(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - - pop!(machine, index); - - let mut load = [0u8; 32]; - #[allow(clippy::needless_range_loop)] - for i in 0..32 { - if let Some(p) = index.checked_add(U256::from(i)) { - if p <= U256::from(usize::MAX) { - let p = p.as_usize(); - if p < machine.contract.input.len() { - load[i] = machine.contract.input[p]; - } - } - } - } - - push_h256!(machine, H256::from(load)); - Return::Continue -} - -pub fn calldatasize(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - - let len = U256::from(machine.contract.input.len()); - push!(machine, len); - Return::Continue -} - -pub fn calldatacopy(machine: &mut Machine) -> Return { - pop!(machine, memory_offset, data_offset, len); - gas_or_fail!(machine, gas::verylowcopy_cost(len)); - let len = as_usize_or_fail!(len, Return::OutOfGas); - if len == 0 { - return Return::Continue; - } - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); - let data_offset = as_usize_saturated!(data_offset); - memory_resize!(machine, memory_offset, len); - - // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - machine - .memory - .set_data(memory_offset, data_offset, len, &machine.contract.input); - Return::Continue -} - -pub fn pop(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - machine.stack.reduce_one() -} - -pub fn mload(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - pop!(machine, index); - - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(machine, index, 32); - push!( - machine, - util::be_to_u256(machine.memory.get_slice(index, 32)) - ); - Return::Continue -} - -pub fn mstore(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - - pop!(machine, index, value); - - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(machine, index, 32); - machine.memory.set_u256(index, value); - Return::Continue -} - -pub fn mstore8(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - - pop!(machine, index, value); - - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(machine, index, 1); - let value = (value.low_u32() & 0xff) as u8; - // Safety: we resized our memory two lines above. - unsafe { machine.memory.set_byte(index, value) } - Return::Continue -} - -pub fn jump(machine: &mut Machine) -> Return { - //gas!(machine, gas::MID); - - pop!(machine, dest); - let dest = as_usize_or_fail!(dest, Return::InvalidJump); - - if machine.contract.is_valid_jump(dest) { - // Safety: In analazis we are checking create our jump table and we do check above to be - // sure that jump is safe to execute. - machine.program_counter = unsafe { machine.contract.code.as_ptr().add(dest) }; - Return::Continue - } else { - Return::InvalidJump - } -} - -pub fn jumpi(machine: &mut Machine) -> Return { - //gas!(machine, gas::HIGH); - - pop!(machine, dest, value); - - if !value.is_zero() { - let dest = as_usize_or_fail!(dest, Return::InvalidJump); - if machine.contract.is_valid_jump(dest) { - // Safety: In analazis we are checking if jump is valid destination and this if. - // make this unsafe block safe. - machine.program_counter = unsafe { machine.contract.code.as_ptr().add(dest) }; - Return::Continue - } else { - Return::InvalidJump - } - } else { - // if we are not doing jump, add next gas block. - machine.add_next_gas_block(machine.program_counter() - 1) - } -} - -pub fn jumpdest(machine: &mut Machine) -> Return { - gas!(machine, gas::JUMPDEST); - machine.add_next_gas_block(machine.program_counter() - 1) -} - -pub fn pc(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - push!(machine, U256::from(machine.program_counter() - 1)); - Return::Continue -} - -pub fn msize(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - push!(machine, U256::from(machine.memory.effective_len())); - Return::Continue -} - -// code padding is needed for contracts - -pub fn push(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - - let start = machine.program_counter; - // Safety: In Analazis we appended needed bytes for bytecode so that we are safe to just add without - // checking if it is out of bound. This makes both of our unsafes block safe to do. - let ret = machine - .stack - .push_slice::(unsafe { core::slice::from_raw_parts(start, N) }); - machine.program_counter = unsafe { machine.program_counter.add(N) }; - ret -} - -pub fn dup(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - machine.stack.dup::() -} - -pub fn swap(machine: &mut Machine) -> Return { - //gas!(machine, gas::VERYLOW); - machine.stack.swap::() -} - -pub fn ret(machine: &mut Machine) -> Return { - // zero gas cost gas!(machine,gas::ZERO); - pop!(machine, start, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - if len == 0 { - machine.return_range = usize::MAX..usize::MAX; - } else { - let offset = as_usize_or_fail!(start, Return::OutOfGas); - memory_resize!(machine, offset, len); - machine.return_range = offset..(offset + len); - } - Return::Return -} - -pub fn revert(machine: &mut Machine) -> Return { - check!(SPEC::enabled(BYZANTINE)); // EIP-140: REVERT instruction - // zero gas cost gas!(machine,gas::ZERO); - pop!(machine, start, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - if len == 0 { - machine.return_range = usize::MAX..usize::MAX; - } else { - let offset = as_usize_or_fail!(start, Return::OutOfGas); - memory_resize!(machine, offset, len); - machine.return_range = offset..(offset + len); - } - Return::Revert -} diff --git a/crates/revm/src/instructions/mod.rs b/crates/revm/src/instructions/mod.rs deleted file mode 100644 index e3d72034c8..0000000000 --- a/crates/revm/src/instructions/mod.rs +++ /dev/null @@ -1,247 +0,0 @@ -#[macro_use] -mod macros; -mod arithmetic; -mod bitwise; -pub(crate) mod gas; -mod i256; -mod misc; -pub mod opcode; -mod system; - -pub use opcode::{OpCode, OPCODE_JUMPMAP}; - -use crate::{ - machine::Machine, - spec::{Spec, SpecId::*}, - CallScheme, Host, -}; -use core::ops::{BitAnd, BitOr, BitXor}; -use primitive_types::U256; - -#[macro_export] -macro_rules! return_ok { - () => { - Return::Continue | Return::Stop | Return::Return | Return::SelfDestruct - }; -} - -#[macro_export] -macro_rules! return_revert { - () => { - Return::Revert | Return::CallTooDeep | Return::OutOfFund - }; -} - -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Return { - //success codes - Continue = 0x00, - Stop = 0x01, - Return = 0x02, - SelfDestruct = 0x03, - - // revert code - Revert = 0x20, // revert opcode - CallTooDeep = 0x21, - OutOfFund = 0x22, - - // error codes - OutOfGas = 0x50, - OpcodeNotFound, - CallNotAllowedInsideStatic, - InvalidOpcode, - InvalidJump, - InvalidMemoryRange, - NotActivated, - StackUnderflow, - StackOverflow, - OutOfOffset, - FatalNotSupported, - GasMaxFeeGreaterThanPriorityFee, - GasPriceLessThenBasefee, - CallerGasLimitMoreThenBlock, - RejectCallerWithCode, //new eip included in london - LackOfFundForGasLimit, - CreateCollision, - OverflowPayment, - Precompile, - - /// Create init code exceeds limit (runtime). - CreateContractLimit, - /// Create contract that begins with EF - CreateContractWithEF, -} - -#[inline(always)] -pub fn eval(opcode: u8, machine: &mut Machine, host: &mut H) -> Return { - match opcode { - /*12_u8..=15_u8 => Return::OpcodeNotFound, - 30_u8..=31_u8 => Return::OpcodeNotFound, - 33_u8..=47_u8 => Return::OpcodeNotFound, - 73_u8..=79_u8 => Return::OpcodeNotFound, - 92_u8..=95_u8 => Return::OpcodeNotFound, - 165_u8..=239_u8 => Return::OpcodeNotFound, - 246_u8..=249_u8 => Return::OpcodeNotFound, - 251_u8..=252_u8 => Return::OpcodeNotFound,*/ - opcode::STOP => Return::Stop, - opcode::ADD => op2_u256_tuple!(machine, overflowing_add), - opcode::MUL => op2_u256_tuple!(machine, overflowing_mul), - opcode::SUB => op2_u256_tuple!(machine, overflowing_sub), - opcode::DIV => op2_u256_fn!(machine, arithmetic::div), - opcode::SDIV => op2_u256_fn!(machine, arithmetic::sdiv), - opcode::MOD => op2_u256_fn!(machine, arithmetic::rem), - opcode::SMOD => op2_u256_fn!(machine, arithmetic::smod), - opcode::ADDMOD => op3_u256_fn!(machine, arithmetic::addmod), - opcode::MULMOD => op3_u256_fn!(machine, arithmetic::mulmod), - opcode::EXP => arithmetic::eval_exp::(machine), - opcode::SIGNEXTEND => op2_u256_fn!(machine, arithmetic::signextend), - opcode::LT => op2_u256_bool_ref!(machine, lt), - opcode::GT => op2_u256_bool_ref!(machine, gt), - opcode::SLT => op2_u256_fn!(machine, bitwise::slt), - opcode::SGT => op2_u256_fn!(machine, bitwise::sgt), - opcode::EQ => op2_u256_bool_ref!(machine, eq), - opcode::ISZERO => op1_u256_fn!(machine, bitwise::iszero), - opcode::AND => op2_u256!(machine, bitand), - opcode::OR => op2_u256!(machine, bitor), - opcode::XOR => op2_u256!(machine, bitxor), - opcode::NOT => op1_u256_fn!(machine, bitwise::not), - opcode::BYTE => op2_u256_fn!(machine, bitwise::byte), - opcode::SHL => op2_u256_fn!( - machine, - bitwise::shl, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SHR => op2_u256_fn!( - machine, - bitwise::shr, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SAR => op2_u256_fn!( - machine, - bitwise::sar, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SHA3 => system::sha3(machine), - - opcode::ADDRESS => system::address(machine), - opcode::BALANCE => system::balance::(machine, host), - opcode::SELFBALANCE => system::selfbalance::(machine, host), - opcode::CODESIZE => misc::codesize(machine), - opcode::CODECOPY => misc::codecopy(machine), - opcode::CALLDATALOAD => misc::calldataload(machine), - opcode::CALLDATASIZE => misc::calldatasize(machine), - opcode::CALLDATACOPY => misc::calldatacopy(machine), - opcode::POP => misc::pop(machine), - opcode::MLOAD => misc::mload(machine), - opcode::MSTORE => misc::mstore(machine), - opcode::MSTORE8 => misc::mstore8(machine), - opcode::JUMP => misc::jump(machine), - opcode::JUMPI => misc::jumpi(machine), - opcode::PC => misc::pc(machine), - opcode::MSIZE => misc::msize(machine), - opcode::JUMPDEST => misc::jumpdest(machine), - opcode::PUSH1 => misc::push::<1>(machine), - opcode::PUSH2 => misc::push::<2>(machine), - opcode::PUSH3 => misc::push::<3>(machine), - opcode::PUSH4 => misc::push::<4>(machine), - opcode::PUSH5 => misc::push::<5>(machine), - opcode::PUSH6 => misc::push::<6>(machine), - opcode::PUSH7 => misc::push::<7>(machine), - opcode::PUSH8 => misc::push::<8>(machine), - opcode::PUSH9 => misc::push::<9>(machine), - opcode::PUSH10 => misc::push::<10>(machine), - opcode::PUSH11 => misc::push::<11>(machine), - opcode::PUSH12 => misc::push::<12>(machine), - opcode::PUSH13 => misc::push::<13>(machine), - opcode::PUSH14 => misc::push::<14>(machine), - opcode::PUSH15 => misc::push::<15>(machine), - opcode::PUSH16 => misc::push::<16>(machine), - opcode::PUSH17 => misc::push::<17>(machine), - opcode::PUSH18 => misc::push::<18>(machine), - opcode::PUSH19 => misc::push::<19>(machine), - opcode::PUSH20 => misc::push::<20>(machine), - opcode::PUSH21 => misc::push::<21>(machine), - opcode::PUSH22 => misc::push::<22>(machine), - opcode::PUSH23 => misc::push::<23>(machine), - opcode::PUSH24 => misc::push::<24>(machine), - opcode::PUSH25 => misc::push::<25>(machine), - opcode::PUSH26 => misc::push::<26>(machine), - opcode::PUSH27 => misc::push::<27>(machine), - opcode::PUSH28 => misc::push::<28>(machine), - opcode::PUSH29 => misc::push::<29>(machine), - opcode::PUSH30 => misc::push::<30>(machine), - opcode::PUSH31 => misc::push::<31>(machine), - opcode::PUSH32 => misc::push::<32>(machine), - opcode::DUP1 => misc::dup::<1>(machine), - opcode::DUP2 => misc::dup::<2>(machine), - opcode::DUP3 => misc::dup::<3>(machine), - opcode::DUP4 => misc::dup::<4>(machine), - opcode::DUP5 => misc::dup::<5>(machine), - opcode::DUP6 => misc::dup::<6>(machine), - opcode::DUP7 => misc::dup::<7>(machine), - opcode::DUP8 => misc::dup::<8>(machine), - opcode::DUP9 => misc::dup::<9>(machine), - opcode::DUP10 => misc::dup::<10>(machine), - opcode::DUP11 => misc::dup::<11>(machine), - opcode::DUP12 => misc::dup::<12>(machine), - opcode::DUP13 => misc::dup::<13>(machine), - opcode::DUP14 => misc::dup::<14>(machine), - opcode::DUP15 => misc::dup::<15>(machine), - opcode::DUP16 => misc::dup::<16>(machine), - - opcode::SWAP1 => misc::swap::<1>(machine), - opcode::SWAP2 => misc::swap::<2>(machine), - opcode::SWAP3 => misc::swap::<3>(machine), - opcode::SWAP4 => misc::swap::<4>(machine), - opcode::SWAP5 => misc::swap::<5>(machine), - opcode::SWAP6 => misc::swap::<6>(machine), - opcode::SWAP7 => misc::swap::<7>(machine), - opcode::SWAP8 => misc::swap::<8>(machine), - opcode::SWAP9 => misc::swap::<9>(machine), - opcode::SWAP10 => misc::swap::<10>(machine), - opcode::SWAP11 => misc::swap::<11>(machine), - opcode::SWAP12 => misc::swap::<12>(machine), - opcode::SWAP13 => misc::swap::<13>(machine), - opcode::SWAP14 => misc::swap::<14>(machine), - opcode::SWAP15 => misc::swap::<15>(machine), - opcode::SWAP16 => misc::swap::<16>(machine), - - opcode::RETURN => misc::ret(machine), - opcode::REVERT => misc::revert::(machine), - opcode::INVALID => Return::InvalidOpcode, - opcode::BASEFEE => system::basefee::(machine, host), - opcode::ORIGIN => system::origin(machine, host), - opcode::CALLER => system::caller(machine), - opcode::CALLVALUE => system::callvalue(machine), - opcode::GASPRICE => system::gasprice(machine, host), - opcode::EXTCODESIZE => system::extcodesize::(machine, host), - opcode::EXTCODEHASH => system::extcodehash::(machine, host), - opcode::EXTCODECOPY => system::extcodecopy::(machine, host), - opcode::RETURNDATASIZE => system::returndatasize::(machine), - opcode::RETURNDATACOPY => system::returndatacopy::(machine), - opcode::BLOCKHASH => system::blockhash(machine, host), - opcode::COINBASE => system::coinbase(machine, host), - opcode::TIMESTAMP => system::timestamp(machine, host), - opcode::NUMBER => system::number(machine, host), - opcode::DIFFICULTY => system::difficulty(machine, host), - opcode::GASLIMIT => system::gaslimit(machine, host), - opcode::SLOAD => system::sload::(machine, host), - opcode::SSTORE => system::sstore::(machine, host), - opcode::GAS => system::gas(machine), - opcode::LOG0 => system::log::(machine, 0, host), - opcode::LOG1 => system::log::(machine, 1, host), - opcode::LOG2 => system::log::(machine, 2, host), - opcode::LOG3 => system::log::(machine, 3, host), - opcode::LOG4 => system::log::(machine, 4, host), - opcode::SELFDESTRUCT => system::selfdestruct::(machine, host), - opcode::CREATE => system::create::(machine, false, host), //check - opcode::CREATE2 => system::create::(machine, true, host), //check - opcode::CALL => system::call::(machine, CallScheme::Call, host), //check - opcode::CALLCODE => system::call::(machine, CallScheme::CallCode, host), //check - opcode::DELEGATECALL => system::call::(machine, CallScheme::DelegateCall, host), //check - opcode::STATICCALL => system::call::(machine, CallScheme::StaticCall, host), //check - opcode::CHAINID => system::chainid::(machine, host), - _ => Return::OpcodeNotFound, - } -} diff --git a/crates/revm/src/instructions/opcode.rs b/crates/revm/src/instructions/opcode.rs index 508d35d434..c535d172f5 100644 --- a/crates/revm/src/instructions/opcode.rs +++ b/crates/revm/src/instructions/opcode.rs @@ -1,6 +1,6 @@ use crate::SpecId; -use super::gas; +use crate::gas; pub struct OpCode(u8); @@ -341,7 +341,7 @@ macro_rules! gas_opcodee { /* 0x59 MSIZE */ OpInfo::gas(gas::BASE), /* 0x5a GAS */ OpInfo::gas_block_end(gas::BASE), /* 0x5b JUMPDEST */ - OpInfo::gas_block_end(0), //gas::JUMPDEST gas is calculated in function call, + OpInfo::gas_block_end(0), // gas::JUMPDEST gas is calculated in function call, /* 0x5c */ OpInfo::none(), /* 0x5d */ OpInfo::none(), /* 0x5e */ OpInfo::none(), diff --git a/crates/revm/src/instructions/stack.rs b/crates/revm/src/instructions/stack.rs new file mode 100644 index 0000000000..c6f539e3b4 --- /dev/null +++ b/crates/revm/src/instructions/stack.rs @@ -0,0 +1,28 @@ +use crate::{interpreter::Interpreter, Return}; + +pub fn pop(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + interp.stack.reduce_one() +} + +pub fn push(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + let start = interp.program_counter; + // Safety: In Analazis we appended needed bytes for bytecode so that we are safe to just add without + // checking if it is out of bound. This makes both of our unsafes block safe to do. + let ret = interp + .stack + .push_slice::(unsafe { core::slice::from_raw_parts(start, N) }); + interp.program_counter = unsafe { interp.program_counter.add(N) }; + ret +} + +pub fn dup(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + interp.stack.dup::() +} + +pub fn swap(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + interp.stack.swap::() +} diff --git a/crates/revm/src/instructions/system.rs b/crates/revm/src/instructions/system.rs index 43488a90e1..9d1f0795e6 100644 --- a/crates/revm/src/instructions/system.rs +++ b/crates/revm/src/instructions/system.rs @@ -1,531 +1,150 @@ -use super::gas; -use crate::{ - machine::Machine, return_ok, return_revert, CallContext, CallScheme, CreateScheme, Host, - Return, Spec, Transfer, -}; -// CallScheme, Capture, CallContext, CreateScheme, , -// , Runtime, Transfer, -// }; -use crate::{alloc::vec::Vec, spec::SpecId::*}; +use crate::{gas, interpreter::Interpreter, Return}; +use crate::{Spec, SpecId::*}; use bytes::Bytes; -use core::cmp::min; -use primitive_types::{H160, H256, U256}; +use primitive_types::{H256, U256}; + use sha3::{Digest, Keccak256}; -pub fn sha3(machine: &mut Machine) -> Return { - pop!(machine, from, len); - gas_or_fail!(machine, gas::sha3_cost(len)); +pub fn sha3(interp: &mut Interpreter) -> Return { + pop!(interp, from, len); + gas_or_fail!(interp, gas::sha3_cost(len)); let len = as_usize_or_fail!(len, Return::OutOfGas); let data = if len == 0 { Bytes::new() - // TODO optimization, we can return hadrcoded value of keccak256:digest(&[]) + // TODO optimization, we can return hardcoded value of keccak256:digest(&[]) } else { let from = as_usize_or_fail!(from, Return::OutOfGas); - memory_resize!(machine, from, len); - Bytes::copy_from_slice(machine.memory.get_slice(from, len)) + memory_resize!(interp, from, len); + Bytes::copy_from_slice(interp.memory.get_slice(from, len)) }; let ret = Keccak256::digest(data.as_ref()); - push_h256!(machine, H256::from_slice(ret.as_slice())); - + push_h256!(interp, H256::from_slice(ret.as_slice())); Return::Continue } -pub fn chainid(machine: &mut Machine, host: &mut H) -> Return { - check!(SPEC::enabled(ISTANBUL)); // EIP-1344: ChainID opcode - //gas!(machine, gas::BASE); - - push!(machine, host.env().cfg.chain_id); - +pub fn address(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + let ret = H256::from(interp.contract.address); + push_h256!(interp, ret); Return::Continue } -pub fn address(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - - let ret = H256::from(machine.contract.address); - push_h256!(machine, ret); - +pub fn caller(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + let ret = H256::from(interp.contract.caller); + push_h256!(interp, ret); Return::Continue } -pub fn balance(machine: &mut Machine, host: &mut H) -> Return { - pop_address!(machine, address); - let (balance, is_cold) = host.balance(address); - gas!( - machine, - if SPEC::enabled(ISTANBUL) { - // EIP-1884: Repricing for trie-size-dependent opcodes - gas::account_access_gas::(is_cold) - } else if SPEC::enabled(TANGERINE) { - 400 - } else { - 20 - } - ); - push!(machine, balance); - +pub fn codesize(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + let size = U256::from(interp.contract.code_size); + push!(interp, size); Return::Continue } -pub fn selfbalance(machine: &mut Machine, host: &mut H) -> Return { - check!(SPEC::enabled(ISTANBUL)); // EIP-1884: Repricing for trie-size-dependent opcodes - //gas!(machine, gas::LOW); - let (balance, _) = host.balance(machine.contract.address); - push!(machine, balance); - - Return::Continue -} - -pub fn basefee(machine: &mut Machine, host: &mut H) -> Return { - check!(SPEC::enabled(LONDON)); // EIP-3198: BASEFEE opcode - //gas!(machine, gas::BASE); - push!(machine, host.env().block.basefee); - - Return::Continue -} - -pub fn origin(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - - let ret = H256::from(host.env().tx.caller); - push_h256!(machine, ret); +pub fn codecopy(interp: &mut Interpreter) -> Return { + pop!(interp, memory_offset, code_offset, len); + gas_or_fail!(interp, gas::verylowcopy_cost(len)); + let len = as_usize_or_fail!(len, Return::OutOfGas); + if len == 0 { + return Return::Continue; + } + let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); + let code_offset = as_usize_saturated!(code_offset); + memory_resize!(interp, memory_offset, len); + // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it + interp + .memory + .set_data(memory_offset, code_offset, len, &interp.contract.code); + Return::Continue +} + +pub fn calldataload(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::VERYLOW); + pop!(interp, index); + let mut load = [0u8; 32]; + #[allow(clippy::needless_range_loop)] + for i in 0..32 { + if let Some(p) = index.checked_add(U256::from(i)) { + if p <= U256::from(usize::MAX) { + let p = p.as_usize(); + if p < interp.contract.input.len() { + load[i] = interp.contract.input[p]; + } + } + } + } + push_h256!(interp, H256::from(load)); Return::Continue } -pub fn caller(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - - let ret = H256::from(machine.contract.caller); - push_h256!(machine, ret); - +pub fn calldatasize(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + let len = U256::from(interp.contract.input.len()); + push!(interp, len); Return::Continue } -pub fn callvalue(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - +pub fn callvalue(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); let mut ret = H256::default(); - machine.contract.value.to_big_endian(&mut ret[..]); - push_h256!(machine, ret); - + interp.contract.value.to_big_endian(&mut ret[..]); + push_h256!(interp, ret); Return::Continue } -pub fn gasprice(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - push!(machine, host.env().effective_gas_price()); - Return::Continue -} - -pub fn extcodesize(machine: &mut Machine, host: &mut H) -> Return { - pop_address!(machine, address); - - let (code, is_cold) = host.code(address); - gas!(machine, gas::account_access_gas::(is_cold)); - - push!(machine, U256::from(code.len())); - - Return::Continue -} - -pub fn extcodehash(machine: &mut Machine, host: &mut H) -> Return { - check!(SPEC::enabled(CONSTANTINOPLE)); // EIP-1052: EXTCODEHASH opcode - pop_address!(machine, address); - let (code_hash, is_cold) = host.code_hash(address); - gas!( - machine, - if SPEC::enabled(ISTANBUL) { - // EIP-1884: Repricing for trie-size-dependent opcodes - gas::account_access_gas::(is_cold) - } else { - 400 - } - ); - push_h256!(machine, code_hash); - - Return::Continue -} - -pub fn extcodecopy(machine: &mut Machine, host: &mut H) -> Return { - pop_address!(machine, address); - pop!(machine, memory_offset, code_offset, len_u256); - - let (code, is_cold) = host.code(address); - gas_or_fail!(machine, gas::extcodecopy_cost::(len_u256, is_cold)); - let len = as_usize_or_fail!(len_u256, Return::OutOfGas); +pub fn calldatacopy(interp: &mut Interpreter) -> Return { + pop!(interp, memory_offset, data_offset, len); + gas_or_fail!(interp, gas::verylowcopy_cost(len)); + let len = as_usize_or_fail!(len, Return::OutOfGas); if len == 0 { return Return::Continue; } let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); - let code_offset = min(as_usize_saturated!(code_offset), code.len()); - memory_resize!(machine, memory_offset, len); + let data_offset = as_usize_saturated!(data_offset); + memory_resize!(interp, memory_offset, len); // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - machine + interp .memory - .set_data(memory_offset, code_offset, len, &code); + .set_data(memory_offset, data_offset, len, &interp.contract.input); Return::Continue } -pub fn returndatasize(machine: &mut Machine) -> Return { - check!(SPEC::enabled(BYZANTINE)); // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY - //gas!(machine, gas::BASE); - - let size = U256::from(machine.return_data_buffer.len()); - push!(machine, size); - +pub fn returndatasize(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY + check!(SPEC::enabled(BYZANTINE)); + let size = U256::from(interp.return_data_buffer.len()); + push!(interp, size); Return::Continue } -pub fn returndatacopy(machine: &mut Machine) -> Return { - check!(SPEC::enabled(BYZANTINE)); // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY - pop!(machine, memory_offset, offset, len); - gas_or_fail!(machine, gas::verylowcopy_cost(len)); +pub fn returndatacopy(interp: &mut Interpreter) -> Return { + // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY + check!(SPEC::enabled(BYZANTINE)); + pop!(interp, memory_offset, offset, len); + gas_or_fail!(interp, gas::verylowcopy_cost(len)); let len = as_usize_or_fail!(len, Return::OutOfGas); let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); let data_offset = as_usize_saturated!(offset); - memory_resize!(machine, memory_offset, len); + memory_resize!(interp, memory_offset, len); let (data_end, overflow) = data_offset.overflowing_add(len); - if overflow || data_end > machine.return_data_buffer.len() { + if overflow || data_end > interp.return_data_buffer.len() { return Return::OutOfOffset; } - - machine.memory.set( + interp.memory.set( memory_offset, - &machine.return_data_buffer[data_offset..data_end], + &interp.return_data_buffer[data_offset..data_end], ); Return::Continue } -pub fn blockhash(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BLOCKHASH); - - pop!(machine, number); - push_h256!(machine, host.block_hash(number)); - - Return::Continue -} - -pub fn coinbase(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - - push_h256!(machine, host.env().block.coinbase.into()); - Return::Continue -} - -pub fn timestamp(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - push!(machine, host.env().block.timestamp); - Return::Continue -} - -pub fn number(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - - push!(machine, host.env().block.number); - Return::Continue -} - -pub fn difficulty(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - - push!(machine, host.env().block.difficulty); - Return::Continue -} - -pub fn gaslimit(machine: &mut Machine, host: &mut H) -> Return { - //gas!(machine, gas::BASE); - - push!(machine, host.env().block.gas_limit); - Return::Continue -} - -pub fn sload(machine: &mut Machine, host: &mut H) -> Return { - pop!(machine, index); - let (value, is_cold) = host.sload(machine.contract.address, index); - gas!(machine, gas::sload_cost::(is_cold)); - push!(machine, value); - Return::Continue -} - -pub fn sstore(machine: &mut Machine, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); - - pop!(machine, index, value); - let (original, old, new, is_cold) = host.sstore(machine.contract.address, index, value); - gas_or_fail!(machine, { - let remaining_gas = machine.gas.remaining(); - gas::sstore_cost::(original, old, new, remaining_gas, is_cold) - }); - refund!(machine, gas::sstore_refund::(original, old, new)); - Return::Continue -} - -pub fn gas(machine: &mut Machine) -> Return { - //gas!(machine, gas::BASE); - - push!(machine, U256::from(machine.gas.remaining())); - machine.add_next_gas_block(machine.program_counter() - 1) -} - -pub fn log(machine: &mut Machine, n: u8, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); - - pop!(machine, offset, len); - gas_or_fail!(machine, gas::log_cost(n, len)); - let len = as_usize_or_fail!(len, Return::OutOfGas); - let data = if len == 0 { - Bytes::new() - } else { - let offset = as_usize_or_fail!(offset, Return::OutOfGas); - memory_resize!(machine, offset, len); - Bytes::copy_from_slice(machine.memory.get_slice(offset, len)) - }; - let n = n as usize; - if machine.stack.len() < n { - return Return::StackUnderflow; - } - - let mut topics = Vec::with_capacity(n); - for _ in 0..(n) { - let mut t = H256::zero(); - // Sefety: stack bounds already checked few lines above - unsafe { machine.stack.pop_unsafe().to_big_endian(t.as_bytes_mut()) }; - topics.push(t); - } - - host.log(machine.contract.address, topics, data); - Return::Continue -} - -pub fn selfdestruct(machine: &mut Machine, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); - pop_address!(machine, target); - - let res = host.selfdestruct(machine.contract.address, target); - - // EIP-3529: Reduction in refunds - if !SPEC::enabled(LONDON) && !res.previously_destroyed { - refund!(machine, gas::SELFDESTRUCT) - } - gas!(machine, gas::selfdestruct_cost::(res)); - - Return::SelfDestruct -} - -fn gas_call_l64_after(machine: &mut Machine) -> Result { - if SPEC::enabled(TANGERINE) { - //EIP-150: Gas cost changes for IO-heavy operations - let gas = machine.gas().remaining(); - Ok(gas - gas / 64) - } else { - Ok(machine.gas().remaining()) - } -} - -pub fn create( - machine: &mut Machine, - is_create2: bool, - host: &mut H, -) -> Return { - check!(!SPEC::IS_STATIC_CALL); - if is_create2 { - check!(SPEC::enabled(CONSTANTINOPLE)); // EIP-1014: Skinny CREATE2 - } - - machine.return_data_buffer = Bytes::new(); - - pop!(machine, value, code_offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - - let code = if len == 0 { - Bytes::new() - } else { - let code_offset = as_usize_or_fail!(code_offset, Return::OutOfGas); - memory_resize!(machine, code_offset, len); - Bytes::copy_from_slice(machine.memory.get_slice(code_offset, len)) - }; - - let scheme = if is_create2 { - pop!(machine, salt); - gas_or_fail!(machine, gas::create2_cost(len)); - CreateScheme::Create2 { salt } - } else { - gas!(machine, gas::CREATE); - CreateScheme::Create - }; - - // take remaining gas and deduce l64 part of it. - let gas_limit = try_or_fail!(gas_call_l64_after::(machine)); - gas!(machine, gas_limit); - - let (reason, address, gas, return_data) = - host.create::(machine.contract.address, scheme, value, code, gas_limit); - machine.return_data_buffer = return_data; - let created_address: H256 = if matches!(reason, return_ok!()) { - address.map(|a| a.into()).unwrap_or_default() - } else { - H256::default() - }; - push_h256!(machine, created_address); - // reimburse gas that is not spend - machine.gas.reimburse_unspend(&reason, gas); - match reason { - Return::FatalNotSupported => Return::FatalNotSupported, - _ => machine.add_next_gas_block(machine.program_counter() - 1), - } -} - -pub fn call( - machine: &mut Machine, - scheme: CallScheme, - host: &mut H, -) -> Return { - match scheme { - CallScheme::DelegateCall => check!(SPEC::enabled(HOMESTEAD)), // EIP-7: DELEGATECALL - CallScheme::StaticCall => check!(SPEC::enabled(BYZANTINE)), // EIP-214: New opcode STATICCALL - _ => (), - } - machine.return_data_buffer = Bytes::new(); - - pop!(machine, local_gas_limit); - pop_address!(machine, to); - let local_gas_limit = if local_gas_limit > U256::from(u64::MAX) { - u64::MAX - } else { - local_gas_limit.as_u64() - }; - - let value = match scheme { - CallScheme::CallCode => { - pop!(machine, value); - value - } - CallScheme::Call => { - pop!(machine, value); - if SPEC::IS_STATIC_CALL && !value.is_zero() { - return Return::CallNotAllowedInsideStatic; - } - value - } - CallScheme::DelegateCall | CallScheme::StaticCall => U256::zero(), - }; - - pop!(machine, in_offset, in_len, out_offset, out_len); - - let in_len = as_usize_or_fail!(in_len, Return::OutOfGas); - let input = if in_len != 0 { - let in_offset = as_usize_or_fail!(in_offset, Return::OutOfGas); - memory_resize!(machine, in_offset, in_len); - Bytes::copy_from_slice(machine.memory.get_slice(in_offset, in_len)) - } else { - Bytes::new() - }; - - let out_len = as_usize_or_fail!(out_len, Return::OutOfGas); - let out_offset = if out_len != 0 { - let out_offset = as_usize_or_fail!(out_offset, Return::OutOfGas); - memory_resize!(machine, out_offset, out_len); - out_offset - } else { - usize::MAX //unrealistic value so we are sure it is not used - }; - - let context = match scheme { - CallScheme::Call | CallScheme::StaticCall => CallContext { - address: to, - caller: machine.contract.address, - apparent_value: value, - }, - CallScheme::CallCode => CallContext { - address: machine.contract.address, - caller: machine.contract.address, - apparent_value: value, - }, - CallScheme::DelegateCall => CallContext { - address: machine.contract.address, - caller: machine.contract.caller, - apparent_value: machine.contract.value, - }, - }; - - let transfer = if scheme == CallScheme::Call { - Transfer { - source: machine.contract.address, - target: to, - value, - } - } else if scheme == CallScheme::CallCode { - Transfer { - source: machine.contract.address, - target: machine.contract.address, - value, - } - } else { - //this is dummy send for StaticCall and DelegateCall, it should do nothing and dont touch anything. - Transfer { - source: machine.contract.address, - target: machine.contract.address, - value: U256::zero(), - } - }; - - // load account and calculate gas cost. - let (is_cold, exist) = host.load_account(to); - let is_new = !exist; - //let is_cold = false; - gas!( - machine, - gas::call_cost::( - value, - is_new, - is_cold, - matches!(scheme, CallScheme::Call | CallScheme::CallCode), - matches!(scheme, CallScheme::Call | CallScheme::StaticCall), - ) - ); - - // take l64 part of gas_limit - let global_gas_limit = try_or_fail!(gas_call_l64_after::(machine)); - let mut gas_limit = min(global_gas_limit, local_gas_limit); - - gas!(machine, gas_limit); - - // add call stipend if there is value to be transfered. - if matches!(scheme, CallScheme::Call | CallScheme::CallCode) && !transfer.value.is_zero() { - gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); - } - let is_static = matches!(scheme, CallScheme::StaticCall); - - // CALL CONTRACT, with static or ordinary spec. - let (reason, gas, return_data) = if is_static { - host.call::(to, transfer, input, gas_limit, context) - } else { - host.call::(to, transfer, input, gas_limit, context) - }; - machine.return_data_buffer = return_data; - - let target_len = min(out_len, machine.return_data_buffer.len()); - // return unspend gas. - machine.gas.reimburse_unspend(&reason, gas); - match reason { - return_ok!() => { - machine - .memory - .set(out_offset, &machine.return_data_buffer[..target_len]); - push!(machine, U256::one()); - } - return_revert!() => { - push!(machine, U256::zero()); - machine - .memory - .set(out_offset, &machine.return_data_buffer[..target_len]); - } - _ => { - push!(machine, U256::zero()); - } - } - machine.add_next_gas_block(machine.program_counter() - 1) +pub fn gas(interp: &mut Interpreter) -> Return { + // gas!(interp, gas::BASE); + push!(interp, U256::from(interp.gas.remaining())); + interp.add_next_gas_block(interp.program_counter() - 1) } diff --git a/crates/revm/src/machine/machine.rs b/crates/revm/src/interpreter.rs similarity index 59% rename from crates/revm/src/machine/machine.rs rename to crates/revm/src/interpreter.rs index afbacc43a0..2211c7fa74 100644 --- a/crates/revm/src/machine/machine.rs +++ b/crates/revm/src/interpreter.rs @@ -1,17 +1,23 @@ +mod contract; +pub(crate) mod memory; +mod stack; + +pub use contract::Contract; +pub use memory::Memory; +pub use stack::Stack; + use crate::{ instructions::{eval, Return}, - return_ok, return_revert, USE_GAS, + Gas, USE_GAS, }; +use crate::{Host, Spec}; use bytes::Bytes; use core::ops::Range; -use super::{contract::Contract, memory::Memory, stack::Stack}; -use crate::{spec::Spec, Host}; - pub const STACK_LIMIT: u64 = 1024; pub const CALL_STACK_LIMIT: u64 = 1024; -pub struct Machine { +pub struct Interpreter { /// Contract information and invoking data pub contract: Contract, /// Program counter. @@ -30,101 +36,7 @@ pub struct Machine { pub call_depth: u64, } -#[derive(Clone, Copy, Debug)] -pub struct Gas { - limit: u64, - used: u64, - memory: u64, - refunded: i64, - all_used_gas: u64, -} -impl Gas { - pub fn new(limit: u64) -> Self { - Self { - limit, - used: 0, - memory: 0, - refunded: 0, - all_used_gas: 0, - } - } - - pub fn reimburse_unspend(&mut self, exit: &Return, other: Gas) { - match *exit { - return_ok!() => { - self.erase_cost(other.remaining()); - self.record_refund(other.refunded()); - } - return_revert!() => { - self.erase_cost(other.remaining()); - } - _ => {} - } - } - - pub fn limit(&self) -> u64 { - self.limit - } - - pub fn memory(&self) -> u64 { - self.memory - } - - pub fn refunded(&self) -> i64 { - self.refunded - } - - pub fn spend(&self) -> u64 { - self.all_used_gas - } - - pub fn remaining(&self) -> u64 { - self.limit - self.all_used_gas - } - - pub fn erase_cost(&mut self, returned: u64) { - self.used -= returned; - self.all_used_gas -= returned; - } - - pub fn record_refund(&mut self, refund: i64) { - self.refunded += refund; - } - - /// Record an explict cost. - #[inline(always)] - pub fn record_cost(&mut self, cost: u64) -> bool { - let (all_used_gas, overflow) = self.all_used_gas.overflowing_add(cost); - if overflow || self.limit < all_used_gas { - return false; - } - - self.used += cost; - self.all_used_gas = all_used_gas; - true - } - - /// used in memory_resize! macro - - pub fn record_memory(&mut self, gas_memory: u64) -> bool { - if gas_memory > self.memory { - let (all_used_gas, overflow) = self.used.overflowing_add(gas_memory); - if overflow || self.limit < all_used_gas { - return false; - } - self.memory = gas_memory; - self.all_used_gas = all_used_gas; - } - true - } - - /// used in gas_refund! macro - pub fn gas_refund(&mut self, refund: i64) { - self.refunded += refund; - } -} - -impl Machine { +impl Interpreter { pub fn new(contract: Contract, gas_limit: u64, call_depth: u64) -> Self { Self { program_counter: contract.code.as_ptr(), @@ -146,7 +58,7 @@ impl Machine { &self.gas } - /// Reference of machine stack. + /// Reference of interp stack. pub fn stack(&self) -> &Stack { &self.stack } @@ -194,7 +106,7 @@ impl Machine { ret = eval::(opcode, self, host); if H::INSPECT { - let ret = host.step_end(ret, self); + let ret = host.step_end(self, SPEC::IS_STATIC_CALL, ret); if ret != Return::Continue { return ret; } @@ -203,7 +115,7 @@ impl Machine { ret } - /// Copy and get the return value of the machine, if any. + /// Copy and get the return value of the interp, if any. pub fn return_value(&self) -> Bytes { // if start is usize max it means that our return len is zero and we need to return empty if self.return_range.start == usize::MAX { diff --git a/crates/revm/src/machine/contract.rs b/crates/revm/src/interpreter/contract.rs similarity index 100% rename from crates/revm/src/machine/contract.rs rename to crates/revm/src/interpreter/contract.rs diff --git a/crates/revm/src/machine/memory.rs b/crates/revm/src/interpreter/memory.rs similarity index 89% rename from crates/revm/src/machine/memory.rs rename to crates/revm/src/interpreter/memory.rs index d17cadca74..ee96119bae 100644 --- a/crates/revm/src/machine/memory.rs +++ b/crates/revm/src/interpreter/memory.rs @@ -134,16 +134,5 @@ mod tests { let next_multiple = x + 32 - (x % 32); assert_eq!(Some(next_multiple), next_multiple_of_32(x.into())); } - - // // next_multiple_of_32 returns None when the next multiple of 32 is too big - // let last_multiple_of_32 = U256::MAX & !U256::from(31); - // for i in 0..63 { - // let x = U256::MAX - U256::from(i); - // if x > last_multiple_of_32 { - // assert_eq!(None, next_multiple_of_32(x)); - // } else { - // assert_eq!(Some(last_multiple_of_32), next_multiple_of_32(x)); - // } - // } } } diff --git a/crates/revm/src/machine/stack.rs b/crates/revm/src/interpreter/stack.rs similarity index 98% rename from crates/revm/src/machine/stack.rs rename to crates/revm/src/interpreter/stack.rs index edcb35d301..5e925f22ae 100644 --- a/crates/revm/src/machine/stack.rs +++ b/crates/revm/src/interpreter/stack.rs @@ -1,4 +1,4 @@ -use crate::{alloc::vec::Vec, util, Return}; +use crate::{alloc::vec::Vec, Return}; use primitive_types::{H256, U256}; pub const STACK_LIMIT: usize = 1024; @@ -184,7 +184,7 @@ impl Stack { if self.data.len() + 1 > STACK_LIMIT { return Err(Return::StackOverflow); } - self.data.push(util::be_to_u256(&value[..])); + self.data.push(U256::from_big_endian(value.as_ref())); Ok(()) } diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index c3a68d1234..e022f2e4f6 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -4,13 +4,13 @@ pub mod db; mod evm; mod evm_impl; +pub(crate) mod gas; mod inspector; mod instructions; -mod machine; +mod interpreter; mod models; -mod spec; +mod specification; mod subroutine; -mod util; pub use evm_impl::{EVMData, Host}; @@ -18,14 +18,15 @@ pub type DummyStateDB = InMemoryDB; pub use db::{Database, DatabaseCommit, InMemoryDB}; pub use evm::{new, EVM}; +pub use gas::Gas; pub use inspector::{Inspector, NoOpInspector, OverrideSpec}; pub use instructions::{ opcode::{self, spec_opcode_gas, OpCode, OPCODE_JUMPMAP}, Return, }; -pub use machine::{Contract, Gas, Machine, Memory, Stack}; +pub use interpreter::{Contract, Interpreter, Memory, Stack}; pub use models::*; -pub use spec::*; +pub use specification::*; pub use subroutine::{Account, Filth, SubRoutine}; extern crate alloc; diff --git a/crates/revm/src/machine/mod.rs b/crates/revm/src/machine/mod.rs deleted file mode 100644 index 3e46138cae..0000000000 --- a/crates/revm/src/machine/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[allow(clippy::module_inception)] -mod machine; - -mod contract; -pub(crate) mod memory; -mod stack; - -pub use contract::Contract; -pub use machine::*; -pub use memory::Memory; -pub use stack::Stack; diff --git a/crates/revm/src/models.rs b/crates/revm/src/models.rs index 89f88145e2..3356838a5b 100644 --- a/crates/revm/src/models.rs +++ b/crates/revm/src/models.rs @@ -68,6 +68,24 @@ impl AccountInfo { } } +pub struct CallInputs { + pub contract: H160, + pub transfer: Transfer, + pub input: Bytes, + pub gas_limit: u64, + pub context: CallContext, +} + +pub struct CreateInputs { + pub caller: H160, + pub scheme: CreateScheme, + pub value: U256, + pub init_code: Bytes, + pub gas_limit: u64, +} + +pub struct CreateData {} + #[derive(Clone, Debug)] pub enum TransactTo { Call(H160), diff --git a/crates/revm/src/spec/mod.rs b/crates/revm/src/spec/mod.rs deleted file mode 100644 index c9585ebf8d..0000000000 --- a/crates/revm/src/spec/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -mod spec_impl; - -use core::convert::TryFrom; -use num_enum::TryFromPrimitive; -use revm_precompiles::SpecId as PrecompileId; -pub use spec_impl::*; - -#[repr(u8)] -#[derive(Debug, Copy, Clone, TryFromPrimitive)] -#[allow(non_camel_case_types)] -pub enum SpecId { - FRONTIER = 1, - HOMESTEAD = 2, - TANGERINE = 3, - SPURIOUS_DRAGON = 4, - BYZANTINE = 5, - CONSTANTINOPLE = 6, - PETERSBURG = 7, - ISTANBUL = 8, - MUIRGLACIER = 9, - BERLIN = 10, - LONDON = 11, - LATEST = 12, -} - -impl SpecId { - pub const fn to_precompile_id(self) -> u8 { - match self { - FRONTIER | HOMESTEAD | TANGERINE | SPURIOUS_DRAGON => PrecompileId::HOMESTEAD as u8, - BYZANTINE | CONSTANTINOPLE | PETERSBURG => PrecompileId::BYZANTINE as u8, - ISTANBUL | MUIRGLACIER => PrecompileId::ISTANBUL as u8, - BERLIN | LONDON | LATEST => PrecompileId::BERLIN as u8, - } - } - - pub fn try_from_u8(spec_id: u8) -> Option { - Self::try_from(spec_id).ok() - } -} - -pub use SpecId::*; - -impl From<&str> for SpecId { - fn from(name: &str) -> Self { - match name { - "Frontier" => SpecId::FRONTIER, - "Homestead" => SpecId::HOMESTEAD, - "Tangerine" => SpecId::TANGERINE, - "Spurious" => SpecId::SPURIOUS_DRAGON, - "Byzantium" => SpecId::BYZANTINE, - "Constantinople" => SpecId::CONSTANTINOPLE, - "Petersburg" => SpecId::PETERSBURG, - "Istanbul" => SpecId::ISTANBUL, - "MuirGlacier" => SpecId::MUIRGLACIER, - "Berlin" => SpecId::BERLIN, - "London" => SpecId::LONDON, - _ => SpecId::LATEST, - } - } -} - -impl SpecId { - #[inline] - pub const fn enabled(our: SpecId, other: SpecId) -> bool { - our as u8 >= other as u8 - } -} diff --git a/crates/revm/src/spec/spec_impl.rs b/crates/revm/src/spec/spec_impl.rs deleted file mode 100644 index e8759f4676..0000000000 --- a/crates/revm/src/spec/spec_impl.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::SpecId; - -pub(crate) trait NotStaticSpec {} - -pub trait Spec: Sized { - /// litle bit of magic. We can have child version of Spec that contains static flag enabled - type STATIC: Spec; - - #[inline(always)] - fn enabled(spec_id: SpecId) -> bool { - Self::SPEC_ID as u8 >= spec_id as u8 - } - const SPEC_ID: SpecId; - /// static flag used in STATIC type; - const IS_STATIC_CALL: bool; - - const ASSUME_PRECOMPILE_HAS_BALANCE: bool; -} - -macro_rules! spec { - ($spec_id:tt) => { - #[allow(non_snake_case)] - mod $spec_id { - use super::{NotStaticSpec, Spec}; - use crate::SpecId; - - pub struct SpecInner; - - pub type SpecImpl = SpecInner; - pub type SpecStaticImpl = SpecInner; - - impl NotStaticSpec for SpecImpl {} - - impl Spec for SpecInner { - type STATIC = SpecInner; - - //specification id - const SPEC_ID: SpecId = SpecId::$spec_id; - - const IS_STATIC_CALL: bool = IS_STATIC_CALL; - - const ASSUME_PRECOMPILE_HAS_BALANCE: bool = ASSUME_PRECOMPILE_HAS_BALANCE; - } - } - }; -} - -spec!(LATEST); -spec!(LONDON); -spec!(BERLIN); -spec!(ISTANBUL); -spec!(BYZANTINE); -spec!(FRONTIER); - -pub use BERLIN::SpecImpl as BerlinSpec; -pub use BYZANTINE::SpecImpl as ByzantineSpec; -pub use FRONTIER::SpecImpl as FrontierSpec; -pub use ISTANBUL::SpecImpl as IstanbulSpec; -pub use LATEST::SpecImpl as LatestSpec; -pub use LONDON::SpecImpl as LondonSpec; diff --git a/crates/revm/src/specification.rs b/crates/revm/src/specification.rs new file mode 100644 index 0000000000..da634e2caa --- /dev/null +++ b/crates/revm/src/specification.rs @@ -0,0 +1,132 @@ +use core::convert::TryFrom; +use num_enum::TryFromPrimitive; +use revm_precompiles::SpecId as PrecompileId; + +#[repr(u8)] +#[derive(Debug, Copy, Clone, TryFromPrimitive)] +#[allow(non_camel_case_types)] +pub enum SpecId { + FRONTIER = 1, + HOMESTEAD = 2, + TANGERINE = 3, + SPURIOUS_DRAGON = 4, + BYZANTINE = 5, + CONSTANTINOPLE = 6, + PETERSBURG = 7, + ISTANBUL = 8, + MUIRGLACIER = 9, + BERLIN = 10, + LONDON = 11, + LATEST = 12, +} + +impl SpecId { + pub const fn to_precompile_id(self) -> u8 { + match self { + FRONTIER | HOMESTEAD | TANGERINE | SPURIOUS_DRAGON => PrecompileId::HOMESTEAD as u8, + BYZANTINE | CONSTANTINOPLE | PETERSBURG => PrecompileId::BYZANTINE as u8, + ISTANBUL | MUIRGLACIER => PrecompileId::ISTANBUL as u8, + BERLIN | LONDON | LATEST => PrecompileId::BERLIN as u8, + } + } + + pub fn try_from_u8(spec_id: u8) -> Option { + Self::try_from(spec_id).ok() + } +} + +pub use SpecId::*; + +impl From<&str> for SpecId { + fn from(name: &str) -> Self { + match name { + "Frontier" => SpecId::FRONTIER, + "Homestead" => SpecId::HOMESTEAD, + "Tangerine" => SpecId::TANGERINE, + "Spurious" => SpecId::SPURIOUS_DRAGON, + "Byzantium" => SpecId::BYZANTINE, + "Constantinople" => SpecId::CONSTANTINOPLE, + "Petersburg" => SpecId::PETERSBURG, + "Istanbul" => SpecId::ISTANBUL, + "MuirGlacier" => SpecId::MUIRGLACIER, + "Berlin" => SpecId::BERLIN, + "London" => SpecId::LONDON, + _ => SpecId::LATEST, + } + } +} + +impl SpecId { + #[inline] + pub const fn enabled(our: SpecId, other: SpecId) -> bool { + our as u8 >= other as u8 + } +} + +pub(crate) trait NotStaticSpec {} + +pub trait Spec: Sized { + /// litle bit of magic. We can have child version of Spec that contains static flag enabled + type STATIC: Spec; + + #[inline(always)] + fn enabled(spec_id: SpecId) -> bool { + Self::SPEC_ID as u8 >= spec_id as u8 + } + const SPEC_ID: SpecId; + /// static flag used in STATIC type; + const IS_STATIC_CALL: bool; + + const ASSUME_PRECOMPILE_HAS_BALANCE: bool; +} + +mod spec_impl { + use super::{NotStaticSpec, Spec}; + + macro_rules! spec { + ($spec_id:tt) => { + #[allow(non_snake_case)] + pub mod $spec_id { + use super::{NotStaticSpec, Spec}; + use crate::SpecId; + + pub struct SpecInner< + const STATIC_CALL: bool, + const ASSUME_PRECOMPILE_HAS_BALANCE: bool, + >; + + pub type SpecImpl = SpecInner; + pub type SpecStaticImpl = SpecInner; + + impl NotStaticSpec for SpecImpl {} + + impl Spec + for SpecInner + { + type STATIC = SpecInner; + + //specification id + const SPEC_ID: SpecId = SpecId::$spec_id; + + const IS_STATIC_CALL: bool = IS_STATIC_CALL; + + const ASSUME_PRECOMPILE_HAS_BALANCE: bool = ASSUME_PRECOMPILE_HAS_BALANCE; + } + } + }; + } + + spec!(LATEST); + spec!(LONDON); + spec!(BERLIN); + spec!(ISTANBUL); + spec!(BYZANTINE); + spec!(FRONTIER); +} + +pub use spec_impl::BERLIN::SpecImpl as BerlinSpec; +pub use spec_impl::BYZANTINE::SpecImpl as ByzantineSpec; +pub use spec_impl::FRONTIER::SpecImpl as FrontierSpec; +pub use spec_impl::ISTANBUL::SpecImpl as IstanbulSpec; +pub use spec_impl::LATEST::SpecImpl as LatestSpec; +pub use spec_impl::LONDON::SpecImpl as LondonSpec; diff --git a/crates/revm/src/util.rs b/crates/revm/src/util.rs deleted file mode 100644 index 284897e52f..0000000000 --- a/crates/revm/src/util.rs +++ /dev/null @@ -1,39 +0,0 @@ -use primitive_types::{H160, H256, U256}; -use sha3::{Digest, Keccak256}; - -#[inline] -pub fn be_to_u256(slice: &[u8]) -> U256 { - arrayref::array_ref!(slice, 24, 8); - U256([ - u64::from_be_bytes(*arrayref::array_ref!(slice, 24, 8)), - u64::from_be_bytes(*arrayref::array_ref!(slice, 16, 8)), - u64::from_be_bytes(*arrayref::array_ref!(slice, 8, 8)), - u64::from_be_bytes(*arrayref::array_ref!(slice, 0, 8)), - ]) -} - -pub fn l64(gas: u64) -> u64 { - gas - gas / 64 -} - -pub fn create_address(caller: H160, nonce: u64) -> H160 { - let mut stream = rlp::RlpStream::new_list(2); - stream.append(&caller); - stream.append(&nonce); - let out = H256::from_slice(Keccak256::digest(&stream.out()).as_slice()); - let out = H160::from_slice(&out.as_bytes()[12..]); - out -} - -/// Get the create address from given scheme. -pub fn create2_address(caller: H160, code_hash: H256, salt: U256) -> H160 { - let mut temp: [u8; 32] = [0; 32]; - salt.to_big_endian(&mut temp); - - let mut hasher = Keccak256::new(); - hasher.update(&[0xff]); - hasher.update(&caller[..]); - hasher.update(&temp); - hasher.update(&code_hash[..]); - H160::from_slice(&hasher.finalize().as_slice()[12..]) -} diff --git a/crates/revm_precompiles/Cargo.toml b/crates/revm_precompiles/Cargo.toml index bd5408e7a1..0ebd0f4761 100644 --- a/crates/revm_precompiles/Cargo.toml +++ b/crates/revm_precompiles/Cargo.toml @@ -13,7 +13,7 @@ bn = { package = "substrate-bn", version = "0.6", default-features = false } bytes = { version = "1.1", default-features = false } k256 = { version = "0.10.1", default-features = false, features = ["ecdsa", "keccak256"], optional = true } num = { version = "0.4.0", default-features = false, features = ["alloc"] } -primitive-types = { version = "0.10", default-features = false, features = ["rlp"] } +primitive-types = { version = "0.11", default-features = false, features = ["rlp"] } ripemd = { version = "0.1", default-features = false } secp256k1 = { version = "0.21.2", default-features = false, features = ["alloc", "recovery"], optional = true } sha2 = { version = "0.10.1", default-features = false } diff --git a/crates/revmjs/Cargo.toml b/crates/revmjs/Cargo.toml index a64a6527bd..20cd8f8282 100644 --- a/crates/revmjs/Cargo.toml +++ b/crates/revmjs/Cargo.toml @@ -12,12 +12,12 @@ version = "0.2.0" crate-type = ["cdylib"] [dependencies] -bn-rs = "0.2" +bn-rs = "0.2.3" bytes = "1.1" getrandom = { version = "0.2", features = ["js"] } hex = "0.4" js-sys = "0.3" -primitive-types = { version = "0.10", default-features = false, features = ["rlp", "rustc-hex"] } +primitive-types = { version = "0.11", default-features = false, features = ["rlp", "rustc-hex"] } # for windows build remove ecrecover features. see more here: https://github.com/bluealloy/revm/issues/3 revm = { path = "../revm", version = "1.1", default-features = false, features = ["k256"] } wasm-bindgen = "0.2"