diff --git a/Cargo.lock b/Cargo.lock index f23fb982c3..a756805ad3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -81,28 +90,16 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty 2.0.0", - "radium 0.7.0", + "funty", + "radium", "tap", - "wyz 0.5.1", + "wyz", ] [[package]] @@ -111,7 +108,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -124,12 +120,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "bn-rs" version = "0.2.4" @@ -365,24 +355,26 @@ dependencies = [ [[package]] name = "ethabi" -version = "16.0.0" +version = "17.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c98847055d934070b90e806e12d3936b787d0a115068981c1d8dfd5dfef5a5" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" dependencies = [ "ethereum-types", "hex", + "once_cell", + "regex", "serde", "serde_json", - "sha3 0.9.1", + "sha3", "thiserror", "uint", ] [[package]] name = "ethbloom" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", "fixed-hash 0.7.0", @@ -393,15 +385,15 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", "fixed-hash 0.7.0", "impl-rlp", "impl-serde 0.3.2", - "primitive-types 0.10.1", + "primitive-types 0.11.1", "uint", ] @@ -478,12 +470,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "funty" version = "2.0.0" @@ -634,7 +620,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.4", + "tokio-util", "tracing", ] @@ -712,6 +698,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + [[package]] name = "hmac" version = "0.12.1" @@ -813,22 +805,13 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -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.2.1", + "parity-scale-codec", ] [[package]] @@ -946,7 +929,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "sha2", - "sha3 0.10.6", + "sha3", ] [[package]] @@ -1210,20 +1193,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] - [[package]] name = "parity-scale-codec" version = "3.2.1" @@ -1231,25 +1200,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" dependencies = [ "arrayvec", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.1.3", + "parity-scale-codec-derive", "serde", ] -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "parity-scale-codec-derive" version = "3.1.3" @@ -1352,12 +1309,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[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 0.7.0", - "impl-codec 0.5.1", + "impl-codec", "impl-rlp", "impl-serde 0.3.2", "uint", @@ -1370,7 +1327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash 0.8.0", - "impl-codec 0.6.0", + "impl-codec", "impl-rlp", "impl-serde 0.4.0", "uint", @@ -1429,12 +1386,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -1480,6 +1431,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1533,16 +1501,18 @@ dependencies = [ "arrayref", "auto_impl", "bytes", + "derive_more", + "fixed-hash 0.8.0", "futures", "hashbrown 0.13.1", "hex", + "hex-literal", "num_enum", - "primitive-types 0.12.1", "revm_precompiles", "rlp", "ruint", "serde", - "sha3 0.10.6", + "sha3", "tokio", "web3", ] @@ -1553,7 +1523,6 @@ version = "0.1.0" dependencies = [ "bytes", "hex", - "primitive-types 0.12.1", "revm", ] @@ -1567,12 +1536,11 @@ dependencies = [ "k256", "num", "once_cell", - "primitive-types 0.12.1", "ripemd", "ruint", "secp256k1 0.24.1", "sha2", - "sha3 0.10.6", + "sha3", "substrate-bn", ] @@ -1584,6 +1552,7 @@ dependencies = [ "hash-db", "hashbrown 0.13.1", "hex", + "hex-literal", "indicatif", "plain_hasher", "primitive-types 0.12.1", @@ -1591,9 +1560,8 @@ dependencies = [ "rlp", "ruint", "serde", - "serde_derive", "serde_json", - "sha3 0.10.6", + "sha3", "structopt", "thiserror", "triehash", @@ -1648,8 +1616,7 @@ dependencies = [ [[package]] name = "ruint" version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad3a104dc8c3867f653b0fec89c65e00b0ceb752718ad282177a7e0f33257ac" +source = "git+https://github.com/recmo/uint#da0489b40dd06a5141be37bfdba2dab8fc836a41" dependencies = [ "bn-rs", "derive_more", @@ -1664,8 +1631,7 @@ dependencies = [ [[package]] name = "ruint-macro" version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1" +source = "git+https://github.com/recmo/uint#da0489b40dd06a5141be37bfdba2dab8fc836a41" [[package]] name = "rustc-hex" @@ -1869,18 +1835,6 @@ dependencies = [ "digest 0.10.6", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - [[package]] name = "sha3" version = "0.10.6" @@ -2157,21 +2111,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -2180,6 +2119,7 @@ checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -2422,9 +2362,8 @@ dependencies = [ [[package]] name = "web3" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f258e254752d210b84fe117b31f1e3cc9cbf04c0d747eb7f8cf7cf5e370f6d" +version = "0.19.0" +source = "git+https://github.com/tomusdrw/rust-web3#c593b722d57da0c2885123867a7d4662a288d6cc" dependencies = [ "arrayvec", "base64", @@ -2451,7 +2390,7 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "tokio-util 0.6.10", + "tokio-util", "url", "web3-async-native-tls", ] @@ -2608,12 +2547,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 87c6e2298a..d465674fa0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,6 @@ codegen-units = 1 [profile.ethtests] inherits = "test" opt-level = 3 + +[patch.crates-io] +ruint = { git = "https://github.com/recmo/uint" } \ No newline at end of file diff --git a/bins/revm-test/Cargo.toml b/bins/revm-test/Cargo.toml index c65f8e80e2..982acc1f90 100644 --- a/bins/revm-test/Cargo.toml +++ b/bins/revm-test/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] bytes = "1.1" hex = "0.4" -primitive-types = { version = "0.12", features = ["rlp"] } revm = { path = "../../crates/revm", version = "2.3.1" } [[bin]] diff --git a/bins/revm-test/src/bin/analysis.rs b/bins/revm-test/src/bin/analysis.rs index 6061c516df..42e9d7c6fb 100644 --- a/bins/revm-test/src/bin/analysis.rs +++ b/bins/revm-test/src/bin/analysis.rs @@ -1,7 +1,6 @@ -use std::{str::FromStr, time::Instant}; +use std::time::Instant; use bytes::Bytes; -use primitive_types::H160; use revm::{db::BenchmarkDB, Bytecode, TransactTo}; extern crate alloc; @@ -13,9 +12,14 @@ fn main() { let mut evm = revm::new(); // execution globals block hash/gas_limit/coinbase/timestamp.. - evm.env.tx.caller = H160::from_str("0x1000000000000000000000000000000000000000").unwrap(); - evm.env.tx.transact_to = - TransactTo::Call(H160::from_str("0x0000000000000000000000000000000000000000").unwrap()); + evm.env.tx.caller = "0x1000000000000000000000000000000000000000" + .parse() + .unwrap(); + evm.env.tx.transact_to = TransactTo::Call( + "0x0000000000000000000000000000000000000000" + .parse() + .unwrap(), + ); //evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap()); evm.env.tx.data = Bytes::from(hex::decode("8035F0CE").unwrap()); evm.env.cfg.perf_all_precompiles_have_balance = true; diff --git a/bins/revm-test/src/bin/snailtracer.rs b/bins/revm-test/src/bin/snailtracer.rs index db2ec11e24..421b320f90 100644 --- a/bins/revm-test/src/bin/snailtracer.rs +++ b/bins/revm-test/src/bin/snailtracer.rs @@ -1,7 +1,6 @@ -use std::{str::FromStr, time::Instant}; +use std::time::Instant; use bytes::Bytes; -use primitive_types::H160; use revm::{db::BenchmarkDB, Bytecode, TransactTo}; extern crate alloc; @@ -14,9 +13,14 @@ pub fn simple_example() { evm.database(BenchmarkDB::new_bytecode(Bytecode::new_raw(contract_data))); // execution globals block hash/gas_limit/coinbase/timestamp.. - evm.env.tx.caller = H160::from_str("0x1000000000000000000000000000000000000000").unwrap(); - evm.env.tx.transact_to = - TransactTo::Call(H160::from_str("0x0000000000000000000000000000000000000000").unwrap()); + evm.env.tx.caller = "0x1000000000000000000000000000000000000000" + .parse() + .unwrap(); + evm.env.tx.transact_to = TransactTo::Call( + "0x0000000000000000000000000000000000000000" + .parse() + .unwrap(), + ); evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap()); let mut elapsed = std::time::Duration::ZERO; diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index 414dbf9fd1..f129efd90c 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -17,14 +17,19 @@ hex = "0.4" indicatif = "0.17" plain_hasher = "0.2" primitive-types = { version = "0.12", features = ["rlp", "serde"] } -revm = { path = "../../crates/revm", version = "2.3.1", default-features = false, features = ["web3db","std","secp256k1"] } +revm = { path = "../../crates/revm", version = "2.3.1", default-features = false, features = [ + "web3db", + "std", + "secp256k1", + "with-serde", +] } rlp = { version = "0.5", default-features = false } -ruint = { version = "1.6.0", features = ["rlp", "serde"] } -serde = "1.0" -serde_derive = "1.0" +ruint = { version = "1.7.0", features = ["rlp", "serde"] } +serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" sha3 = { version = "0.10", default-features = false } structopt = "0.3" thiserror = "1.0" triehash = "0.8" walkdir = "2.3" +hex-literal = "0.3" diff --git a/bins/revme/src/cli_env.rs b/bins/revme/src/cli_env.rs index 0f2a5feabb..e481637fa9 100644 --- a/bins/revme/src/cli_env.rs +++ b/bins/revme/src/cli_env.rs @@ -1,9 +1,7 @@ use std::str::FromStr; use bytes::Bytes; -use primitive_types::H160; -use revm::{Env, TransactTo}; -use ruint::aliases::U256; +use revm::{Env, TransactTo, B160, U256}; use structopt::StructOpt; #[derive(StructOpt, Clone, Debug)] @@ -65,8 +63,8 @@ pub struct CliEnvBlock { pub number: Option, /// Coinbase or miner or address that created and signed the block. /// Address where we are going to send gas spend - #[structopt(long = "env.block.coinbase", parse(try_from_str = parse_h160))] - pub coinbase: Option, + #[structopt(long = "env.block.coinbase", parse(try_from_str = parse_b160))] + pub coinbase: Option, #[structopt(long = "env.block.timestamp")] pub timestamp: Option, #[structopt(long = "env.block.difficulty")] @@ -79,16 +77,16 @@ pub struct CliEnvBlock { #[derive(StructOpt, Clone, Debug)] pub struct CliEnvTx { /// Caller or Author or tx signer - #[structopt(long = "env.tx.caller", parse(try_from_str = parse_h160))] - pub caller: Option, + #[structopt(long = "env.tx.caller", parse(try_from_str = parse_b160))] + pub caller: Option, #[structopt(long = "env.tx.gas_limit")] pub tx_gas_limit: Option, #[structopt(long = "env.tx.gas_price")] pub gas_price: Option, #[structopt(long = "env.tx.gas_priority_fee")] pub gas_priority_fee: Option, - #[structopt(long = "env.tx.to", parse(try_from_str = parse_h160))] - pub transact_to: Option, + #[structopt(long = "env.tx.to", parse(try_from_str = parse_b160))] + pub transact_to: Option, #[structopt(long = "env.tx.value")] pub value: Option, #[structopt(long = "env.tx.data", parse(try_from_str = parse_hex))] @@ -98,13 +96,13 @@ pub struct CliEnvTx { #[structopt(long = "env.tx.nonce")] pub nonce: Option, //#[structopt(long = "env.")] - //TODO pub access_list: Vec<(H160, Vec)>, + //TODO pub access_list: Vec<(B160, Vec)>, } fn parse_hex(src: &str) -> Result { Ok(Bytes::from(hex::decode(src)?)) } -pub fn parse_h160(input: &str) -> Result::Err> { - H160::from_str(input) +pub fn parse_b160(input: &str) -> Result::Err> { + B160::from_str(input) } diff --git a/bins/revme/src/statetest/cmd.rs b/bins/revme/src/statetest/cmd.rs index 7e4563a34a..4ca4b588ae 100644 --- a/bins/revme/src/statetest/cmd.rs +++ b/bins/revme/src/statetest/cmd.rs @@ -7,6 +7,8 @@ use structopt::StructOpt; pub struct Cmd { #[structopt(required = true)] path: Vec, + #[structopt(short = "s", long)] + single_thread: bool, } impl Cmd { @@ -14,7 +16,7 @@ impl Cmd { for path in &self.path { println!("Start running tests on: {path:?}"); let test_files = find_all_json_tests(path); - run(test_files)? + run(test_files, self.single_thread)? } Ok(()) } diff --git a/bins/revme/src/statetest/merkle_trie.rs b/bins/revme/src/statetest/merkle_trie.rs index 80e5f43608..7ff6116580 100644 --- a/bins/revme/src/statetest/merkle_trie.rs +++ b/bins/revme/src/statetest/merkle_trie.rs @@ -2,34 +2,36 @@ use bytes::Bytes; use hash_db::Hasher; use plain_hasher::PlainHasher; use primitive_types::{H160, H256}; -use revm::{db::DbAccount, Log}; +use revm::{common::keccak256, db::DbAccount, Log, B160, B256, U256}; use rlp::RlpStream; -use ruint::aliases::U256; use sha3::{Digest, Keccak256}; use triehash::sec_trie_root; -pub fn log_rlp_hash(logs: Vec) -> H256 { +pub fn log_rlp_hash(logs: Vec) -> B256 { //https://github.com/ethereum/go-ethereum/blob/356bbe343a30789e77bb38f25983c8f2f2bfbb47/cmd/evm/internal/t8ntool/execution.go#L255 let mut stream = RlpStream::new(); stream.begin_unbounded_list(); for log in logs { stream.begin_list(3); - stream.append(&log.address); - stream.append_list(&log.topics); + stream.append(&log.address.0.as_ref()); + stream.begin_unbounded_list(); + for topic in log.topics { + stream.append(&topic.0.as_ref()); + } + stream.finalize_unbounded_list(); stream.append(&log.data); } stream.finalize_unbounded_list(); let out = stream.out().freeze(); - let out = Keccak256::digest(out); - H256::from_slice(out.as_slice()) + keccak256(&out) } -pub fn state_merkle_trie_root(accounts: impl Iterator) -> H256 { +pub fn state_merkle_trie_root(accounts: impl Iterator) -> B256 { let vec = accounts .map(|(address, info)| { let acc_root = trie_account_rlp(&info); - (address, acc_root) + (H160::from(address.0), acc_root) }) .collect(); @@ -46,19 +48,20 @@ pub fn trie_account_rlp(acc: &DbAccount) -> Bytes { acc.storage .iter() .filter(|(_k, &v)| v != U256::ZERO) - .map(|(k, v)| (H256::from(k.to_be_bytes()), rlp::encode(v))), + .map(|(&k, v)| (H256::from(k.to_be_bytes()), rlp::encode(v))), ) }); - stream.append(&acc.info.code_hash.as_bytes()); + stream.append(&acc.info.code_hash.0.as_ref()); stream.out().freeze() } -pub fn trie_root(acc_data: Vec<(H160, Bytes)>) -> H256 { - sec_trie_root::(acc_data.into_iter()) +pub fn trie_root(acc_data: Vec<(H160, Bytes)>) -> B256 { + B256(sec_trie_root::(acc_data.into_iter()).0) } #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct KeccakHasher; + impl Hasher for KeccakHasher { type Out = H256; type StdHasher = PlainHasher; diff --git a/bins/revme/src/statetest/models/deserializer.rs b/bins/revme/src/statetest/models/deserializer.rs index 16c2d04952..fdc5e8d2ba 100644 --- a/bins/revme/src/statetest/models/deserializer.rs +++ b/bins/revme/src/statetest/models/deserializer.rs @@ -1,8 +1,7 @@ use std::str::FromStr; use bytes::Bytes; -use primitive_types::H160; -use ruint::aliases::U256; +use revm::{B160, U256}; use serde::{ de::{self, Error}, Deserialize, @@ -50,7 +49,7 @@ where Ok(out) } -pub fn deserialize_maybe_empty<'de, D>(deserializer: D) -> Result, D::Error> +pub fn deserialize_maybe_empty<'de, D>(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { @@ -58,7 +57,7 @@ where if string.is_empty() { return Ok(None); } - Ok(Some(H160::from_str(&string).map_err(D::Error::custom)?)) + Ok(Some(B160::from_str(&string).map_err(D::Error::custom)?)) } pub fn deserialize_str_as_bytes<'de, D>(deserializer: D) -> Result diff --git a/bins/revme/src/statetest/models/mod.rs b/bins/revme/src/statetest/models/mod.rs index 545dbc1e1b..fa8ca7a95e 100644 --- a/bins/revme/src/statetest/models/mod.rs +++ b/bins/revme/src/statetest/models/mod.rs @@ -1,13 +1,12 @@ use bytes::Bytes; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; +use revm::{B160, B256, U256}; use std::collections::{BTreeMap, HashMap}; mod deserializer; mod spec; use deserializer::*; -use serde_derive::*; +use serde::Deserialize; pub use self::spec::SpecName; @@ -17,7 +16,7 @@ pub struct TestSuit(pub BTreeMap); #[derive(Debug, PartialEq, Eq, Deserialize)] pub struct TestUnit { pub env: Env, - pub pre: HashMap, + pub pre: HashMap, pub post: BTreeMap>, pub transaction: TransactionParts, } @@ -26,11 +25,11 @@ pub struct TestUnit { #[derive(Debug, PartialEq, Eq, Deserialize)] pub struct Test { /// Post state hash - pub hash: H256, + pub hash: B256, /// Indexes pub indexes: TxPartIndices, // logs - pub logs: H256, + pub logs: B256, #[serde(default)] #[serde(deserialize_with = "deserialize_opt_str_as_bytes")] pub txbytes: Option, @@ -58,7 +57,7 @@ pub struct AccountInfo { #[derive(Debug, PartialEq, Eq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Env { - pub current_coinbase: H160, + pub current_coinbase: B160, #[serde(default, deserialize_with = "deserialize_str_as_u256")] pub current_difficulty: U256, #[serde(deserialize_with = "deserialize_str_as_u256")] @@ -68,7 +67,7 @@ pub struct Env { #[serde(deserialize_with = "deserialize_str_as_u256")] pub current_timestamp: U256, pub current_base_fee: Option, - pub previous_hash: H256, + pub previous_hash: B256, } #[derive(Debug, PartialEq, Eq, Deserialize)] @@ -80,9 +79,9 @@ pub struct TransactionParts { pub gas_limit: Vec, pub gas_price: Option, pub nonce: U256, - pub secret_key: Option, + pub secret_key: Option, #[serde(deserialize_with = "deserialize_maybe_empty")] - pub to: Option, + pub to: Option, pub value: Vec, pub max_fee_per_gas: Option, pub max_priority_fee_per_gas: Option, @@ -91,8 +90,8 @@ pub struct TransactionParts { #[derive(Debug, PartialEq, Eq, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct AccessListItem { - pub address: H160, - pub storage_keys: Vec, + pub address: B160, + pub storage_keys: Vec, } pub type AccessList = Vec; @@ -101,6 +100,7 @@ pub type AccessList = Vec; mod tests { use super::*; + use revm::B160; use serde_json::Error; #[test] @@ -116,4 +116,18 @@ mod tests { println!("out:{out:?}"); Ok(()) } + + #[test] + pub fn serialize_b160() -> Result<(), Error> { + let json = r#"{"_item":"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"}"#; + + #[derive(Deserialize, Debug)] + pub struct Test { + _item: B160, + } + + let out: Test = serde_json::from_str(json)?; + println!("out:{out:?}"); + Ok(()) + } } diff --git a/bins/revme/src/statetest/models/spec.rs b/bins/revme/src/statetest/models/spec.rs index 4da99fb6ae..b7ad099c1d 100644 --- a/bins/revme/src/statetest/models/spec.rs +++ b/bins/revme/src/statetest/models/spec.rs @@ -1,5 +1,5 @@ use revm::SpecId; -use serde_derive::*; +use serde::Deserialize; #[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Ord, Deserialize)] pub enum SpecName { @@ -25,6 +25,8 @@ pub enum SpecName { MergeEOF, #[serde(alias = "Merge+3860")] MergeMeterInitCode, + #[serde(alias = "Merge+3855")] + MergePush0, } impl SpecName { @@ -44,6 +46,7 @@ impl SpecName { Self::Merge => SpecId::MERGE, Self::MergeEOF => SpecId::MERGE_EOF, Self::MergeMeterInitCode => SpecId::MERGE_EOF, + Self::MergePush0 => SpecId::MERGE_EOF, Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => { panic!("Overriden with PETERSBURG") } //_ => panic!("Conversion failed"), diff --git a/bins/revme/src/statetest/runner.rs b/bins/revme/src/statetest/runner.rs index 9d0dde6842..09cf5eff81 100644 --- a/bins/revme/src/statetest/runner.rs +++ b/bins/revme/src/statetest/runner.rs @@ -2,17 +2,16 @@ use std::{ collections::HashMap, ffi::OsStr, path::{Path, PathBuf}, - str::FromStr, sync::{atomic::AtomicBool, Arc, Mutex}, time::{Duration, Instant}, }; -use sha3::{Digest, Keccak256}; - use indicatif::ProgressBar; -use primitive_types::{H160, H256}; -use revm::{db::AccountState, Bytecode, CreateScheme, Env, ExecutionResult, SpecId, TransactTo}; -use ruint::aliases::U256; +use revm::{ + bits::{B160, B256}, + db::AccountState, + Bytecode, CreateScheme, Env, ExecutionResult, SpecId, TransactTo, U256, +}; use std::sync::atomic::Ordering; use walkdir::{DirEntry, WalkDir}; @@ -21,6 +20,8 @@ use super::{ models::{SpecName, TestSuit}, trace::CustomPrintTracer, }; +use hex_literal::hex; +use revm::common::keccak256; use thiserror::Error; #[derive(Debug, Error)] @@ -29,15 +30,15 @@ pub enum TestError { RootMissmatch { spec_id: SpecId, id: usize, - got: H256, - expect: H256, + got: B256, + expect: B256, }, #[error("Serde json error")] SerdeDeserialize(#[from] serde_json::Error), #[error("Internal system error")] SystemError, #[error("Unknown private key: {private_key:?}")] - UnknownPrivateKey { private_key: H256 }, + UnknownPrivateKey { private_key: B256 }, } pub fn find_all_json_tests(path: &Path) -> Vec { @@ -96,34 +97,40 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< let map_caller_keys: HashMap<_, _> = vec![ ( - H256::from_str("0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - .unwrap(), - H160::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(), + B256(hex!( + "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + )), + B160(hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b")), ), ( - H256::from_str("0xc85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4") - .unwrap(), - H160::from_str("0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826").unwrap(), + B256(hex!( + "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4" + )), + B160(hex!("cd2a3d9f938e13cd947ec05abc7fe734df8dd826")), ), ( - H256::from_str("0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d") - .unwrap(), - H160::from_str("0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap(), + B256(hex!( + "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d" + )), + B160(hex!("82a978b3f5962a5b0957d9ee9eef472ee55b42f1")), ), ( - H256::from_str("0x6a7eeac5f12b409d42028f66b0b2132535ee158cfda439e3bfdd4558e8f4bf6c") - .unwrap(), - H160::from_str("0xc9c5a15a403e41498b6f69f6f89dd9f5892d21f7").unwrap(), + B256(hex!( + "6a7eeac5f12b409d42028f66b0b2132535ee158cfda439e3bfdd4558e8f4bf6c" + )), + B160(hex!("c9c5a15a403e41498b6f69f6f89dd9f5892d21f7")), ), ( - H256::from_str("0xa95defe70ebea7804f9c3be42d20d24375e2a92b9d9666b832069c5f3cd423dd") - .unwrap(), - H160::from_str("0x3fb1cd2cd96c6d5c0b5eb3322d807b34482481d4").unwrap(), + B256(hex!( + "a95defe70ebea7804f9c3be42d20d24375e2a92b9d9666b832069c5f3cd423dd" + )), + B160(hex!("3fb1cd2cd96c6d5c0b5eb3322d807b34482481d4")), ), ( - H256::from_str("0xfe13266ff57000135fb9aa854bbfe455d8da85b21f626307bf3263a0c2a8e7fe") - .unwrap(), - H160::from_str("0xdcc5ba93a1ed7e045690d722f2bf460a51c61415").unwrap(), + B256(hex!( + "fe13266ff57000135fb9aa854bbfe455d8da85b21f626307bf3263a0c2a8e7fe" + )), + B160(hex!("dcc5ba93a1ed7e045690d722f2bf460a51c61415")), ), ] .into_iter() @@ -135,7 +142,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< for (address, info) in unit.pre.iter() { let acc_info = revm::AccountInfo { balance: info.balance, - code_hash: H256::from_slice(Keccak256::digest(&info.code).as_slice()), //try with dummy hash. + code_hash: keccak256(&info.code), // try with dummy hash. code: Some(Bytecode::new_raw(info.code.clone())), nonce: info.nonce, }; @@ -181,6 +188,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< | SpecName::Constantinople | SpecName::MergeEOF | SpecName::MergeMeterInitCode + | SpecName::MergePush0 ) { continue; } @@ -210,8 +218,8 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< ( item.address, item.storage_keys - .iter() - .map(|f| U256::from_be_bytes(f.0)) + .into_iter() + .map(|key| U256::from_be_bytes(key.0)) .collect::>(), ) }) @@ -287,13 +295,14 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< Ok(()) } -pub fn run(test_files: Vec) -> Result<(), TestError> { +pub fn run(test_files: Vec, single_thread: bool) -> Result<(), TestError> { let endjob = Arc::new(AtomicBool::new(false)); let console_bar = Arc::new(ProgressBar::new(test_files.len() as u64)); let mut joins: Vec>> = Vec::new(); let queue = Arc::new(Mutex::new((0, test_files))); let elapsed = Arc::new(Mutex::new(std::time::Duration::ZERO)); - for _ in 0..10 { + let num_threads = if single_thread { 1 } else { 10 }; + for _ in 0..num_threads { let queue = queue.clone(); let endjob = endjob.clone(); let console_bar = console_bar.clone(); diff --git a/bins/revme/src/statetest/trace.rs b/bins/revme/src/statetest/trace.rs index fbbd76577a..a70b319159 100644 --- a/bins/revme/src/statetest/trace.rs +++ b/bins/revme/src/statetest/trace.rs @@ -1,11 +1,10 @@ use bytes::Bytes; -use primitive_types::H160; pub use revm::Inspector; use revm::{ + bits::B160, opcode::{self}, CallInputs, CreateInputs, Database, EVMData, Gas, GasInspector, Return, }; - #[derive(Clone)] pub struct CustomPrintTracer { gas_inspector: GasInspector, @@ -93,10 +92,10 @@ impl Inspector for CustomPrintTracer { data: &mut EVMData<'_, DB>, inputs: &CreateInputs, ret: Return, - address: Option, + address: Option, remaining_gas: Gas, out: Bytes, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { self.gas_inspector .create_end(data, inputs, ret, address, remaining_gas, out.clone()); (ret, address, remaining_gas, out) @@ -123,7 +122,7 @@ impl Inspector for CustomPrintTracer { &mut self, _data: &mut EVMData<'_, DB>, inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { println!( "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}", inputs.caller, @@ -136,7 +135,7 @@ impl Inspector for CustomPrintTracer { } fn selfdestruct(&mut self) { - //, address: H160, target: H160) { + //, address: B160, target: B160) { println!("SELFDESTRUCT on "); //{:?} target: {:?}", address, target); } } diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index cd5cf69a28..4a945719e6 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -17,13 +17,17 @@ futures = { version = "0.3.24", optional = true } hashbrown = { version = "0.13" } hex = { version = "0.4", optional = true } num_enum = { version = "0.5", default-features = false } # used for SpecId from u8 cast -primitive-types = { version = "0.12", default-features = false, features = ["rlp"] } revm_precompiles = { path = "../revm_precompiles", version = "1.1.2", default-features = false } rlp = { version = "0.5", default-features = false } # used for create2 address calculation -ruint = { version = "1.6.0", features = ["rlp"] } +ruint = { version = "1.7.0", features = ["primitive-types", "rlp",] } serde = { version = "1.0", features = ["derive","rc"], optional = true } tokio = { version = "1.21", features = ["rt-multi-thread", "macros"], optional = true } -web3 = { version = "0.18", optional = true } +web3 = { git = "https://github.com/tomusdrw/rust-web3", version = "0.19", optional = true } + +# bits B256 B160 crate +fixed-hash = { version = "0.8", default-features = false, features = ["rustc-hex"]} +hex-literal = "0.3" +derive_more = "0.99" # sha3 keccak hasher sha3 = { version = "0.10", default-features = false, features = []} @@ -36,8 +40,8 @@ no_gas_measuring = [] optional_block_gas_limit = [] optional_eip3607 = [] optional_gas_refund = [] -std = ["bytes/std", "num_enum/std", "primitive-types/std", "rlp/std"] +std = ["bytes/std", "num_enum/std", "rlp/std"] secp256k1 = ["revm_precompiles/secp256k1"] k256 = ["revm_precompiles/k256_ecrecover"] web3db = ["futures", "tokio", "web3"] -with-serde = ["serde", "primitive-types/serde", "hex", "hex/serde", "hashbrown/serde"] +with-serde = ["serde", "hex", "hex/serde", "hashbrown/serde"] diff --git a/crates/revm/src/bits.rs b/crates/revm/src/bits.rs new file mode 100644 index 0000000000..8672a93ddc --- /dev/null +++ b/crates/revm/src/bits.rs @@ -0,0 +1,296 @@ +use derive_more::{AsRef, Deref}; +use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions}; + +construct_fixed_hash! { + /// revm 256 bits type. + #[derive(AsRef,Deref)] + pub struct B256(32); +} + +construct_fixed_hash! { + /// revm 160 bits type. + #[derive(AsRef,Deref)] + pub struct B160(20); +} + +impl From for B160 { + fn from(fr: u64) -> Self { + let x_bytes = fr.to_be_bytes(); + B160([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x_bytes[0], x_bytes[1], x_bytes[2], x_bytes[3], + x_bytes[4], x_bytes[5], x_bytes[6], x_bytes[7], + ]) + } +} + +impl_fixed_hash_conversions!(B256, B160); + +#[cfg(feature = "with-serde")] +impl serde::Serialize for B256 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut slice = [0u8; 2 + 2 * 32]; + serialize::serialize_raw(&mut slice, &self.0, serializer) + } +} +#[cfg(feature = "with-serde")] +impl<'de> serde::Deserialize<'de> for B256 { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let mut bytes = [0u8; 32]; + serialize::deserialize_check_len(deserializer, serialize::ExpectedLen::Exact(&mut bytes))?; + Ok(B256(bytes)) + } +} +#[cfg(feature = "with-serde")] +impl serde::Serialize for B160 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut slice = [0u8; 2 + 2 * 20]; + serialize::serialize_raw(&mut slice, &self.0, serializer) + } +} + +#[cfg(feature = "with-serde")] +impl<'de> serde::Deserialize<'de> for B160 { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let mut bytes = [0u8; 20]; + serialize::deserialize_check_len(deserializer, serialize::ExpectedLen::Exact(&mut bytes))?; + Ok(B160(bytes)) + } +} + +// code optained from: https://docs.rs/impl-serde/0.4.0/impl_serde/ +#[cfg(feature = "with-serde")] +mod serialize { + + use alloc::{string::String, vec::Vec}; + use core::{fmt, result::Result}; + use serde::{de, Deserializer, Serializer}; + + static CHARS: &[u8] = b"0123456789abcdef"; + + /// Serialize given bytes to a 0x-prefixed hex string. + /// + /// If `skip_leading_zero` initial 0s will not be printed out, + /// unless the byte string is empty, in which case `0x0` will be returned. + /// The results are consistent with `serialize_uint` output if the flag is + /// on and `serialize_raw` if the flag is off. + pub fn to_hex(bytes: &[u8], skip_leading_zero: bool) -> String { + let bytes = if skip_leading_zero { + let non_zero = bytes.iter().take_while(|b| **b == 0).count(); + let bytes = &bytes[non_zero..]; + if bytes.is_empty() { + return "0x0".into(); + } else { + bytes + } + } else if bytes.is_empty() { + return "0x".into(); + } else { + bytes + }; + + let mut slice = vec![0u8; (bytes.len() + 1) * 2]; + to_hex_raw(&mut slice, bytes, skip_leading_zero).into() + } + + fn to_hex_raw<'a>(v: &'a mut [u8], bytes: &[u8], skip_leading_zero: bool) -> &'a str { + assert!(v.len() > 1 + bytes.len() * 2); + + v[0] = b'0'; + v[1] = b'x'; + + let mut idx = 2; + let first_nibble = bytes[0] >> 4; + if first_nibble != 0 || !skip_leading_zero { + v[idx] = CHARS[first_nibble as usize]; + idx += 1; + } + v[idx] = CHARS[(bytes[0] & 0xf) as usize]; + idx += 1; + + for &byte in bytes.iter().skip(1) { + v[idx] = CHARS[(byte >> 4) as usize]; + v[idx + 1] = CHARS[(byte & 0xf) as usize]; + idx += 2; + } + + // SAFETY: all characters come either from CHARS or "0x", therefore valid UTF8 + unsafe { core::str::from_utf8_unchecked(&v[0..idx]) } + } + + /// Decoding bytes from hex string error. + #[derive(Debug, PartialEq, Eq)] + pub enum FromHexError { + /// Invalid (non-hex) character encountered. + InvalidHex { + /// The unexpected character. + character: char, + /// Index of that occurrence. + index: usize, + }, + } + + #[cfg(feature = "std")] + impl std::error::Error for FromHexError {} + + impl fmt::Display for FromHexError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::InvalidHex { character, index } => { + write!(fmt, "invalid hex character: {}, at {}", character, index) + } + } + } + } + + /// Decode given (both 0x-prefixed or not) hex string into a vector of bytes. + /// + /// Returns an error if non-hex characters are present. + pub fn from_hex(v: &str) -> Result, FromHexError> { + let (v, stripped) = v.strip_prefix("0x").map_or((v, false), |v| (v, true)); + + let mut bytes = vec![0u8; (v.len() + 1) / 2]; + from_hex_raw(v, &mut bytes, stripped)?; + Ok(bytes) + } + + /// Decode given 0x-prefix-stripped hex string into provided slice. + /// Used internally by `from_hex` and `deserialize_check_len`. + /// + /// The method will panic if `bytes` have incorrect length (make sure to allocate enough beforehand). + fn from_hex_raw(v: &str, bytes: &mut [u8], stripped: bool) -> Result { + let bytes_len = v.len(); + let mut modulus = bytes_len % 2; + let mut buf = 0; + let mut pos = 0; + for (index, byte) in v.bytes().enumerate() { + buf <<= 4; + + match byte { + b'A'..=b'F' => buf |= byte - b'A' + 10, + b'a'..=b'f' => buf |= byte - b'a' + 10, + b'0'..=b'9' => buf |= byte - b'0', + b' ' | b'\r' | b'\n' | b'\t' => { + buf >>= 4; + continue; + } + b => { + let character = char::from(b); + return Err(FromHexError::InvalidHex { + character, + index: index + if stripped { 2 } else { 0 }, + }); + } + } + + modulus += 1; + if modulus == 2 { + modulus = 0; + bytes[pos] = buf; + pos += 1; + } + } + + Ok(pos) + } + + /// Serializes a slice of bytes. + pub fn serialize_raw( + slice: &mut [u8], + bytes: &[u8], + serializer: S, + ) -> Result + where + S: Serializer, + { + if bytes.is_empty() { + serializer.serialize_str("0x") + } else { + serializer.serialize_str(to_hex_raw(slice, bytes, false)) + } + } + + /// Expected length of bytes vector. + #[derive(Debug, PartialEq, Eq)] + pub enum ExpectedLen<'a> { + /// Exact length in bytes. + Exact(&'a mut [u8]), + /// A bytes length between (min; slice.len()]. + Between(usize, &'a mut [u8]), + } + + impl<'a> fmt::Display for ExpectedLen<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + ExpectedLen::Exact(ref v) => write!(fmt, "length of {}", v.len() * 2), + ExpectedLen::Between(min, ref v) => { + write!(fmt, "length between ({}; {}]", min * 2, v.len() * 2) + } + } + } + } + + /// Deserialize into vector of bytes with additional size check. + /// Returns number of bytes written. + pub fn deserialize_check_len<'a, 'de, D>( + deserializer: D, + len: ExpectedLen<'a>, + ) -> Result + where + D: Deserializer<'de>, + { + struct Visitor<'a> { + len: ExpectedLen<'a>, + } + + impl<'a, 'b> de::Visitor<'b> for Visitor<'a> { + type Value = usize; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "a (both 0x-prefixed or not) hex string with {}", + self.len + ) + } + + fn visit_str(self, v: &str) -> Result { + let (v, stripped) = v.strip_prefix("0x").map_or((v, false), |v| (v, true)); + + let len = v.len(); + let is_len_valid = match self.len { + ExpectedLen::Exact(ref slice) => len == 2 * slice.len(), + ExpectedLen::Between(min, ref slice) => len <= 2 * slice.len() && len > 2 * min, + }; + + if !is_len_valid { + return Err(E::invalid_length(v.len(), &self)); + } + + let bytes = match self.len { + ExpectedLen::Exact(slice) => slice, + ExpectedLen::Between(_, slice) => slice, + }; + + from_hex_raw(v, bytes, stripped).map_err(E::custom) + } + + fn visit_string(self, v: String) -> Result { + self.visit_str(&v) + } + } + + deserializer.deserialize_str(Visitor { len }) + } +} diff --git a/crates/revm/src/common.rs b/crates/revm/src/common.rs index 6bf1442082..929dd4e19e 100644 --- a/crates/revm/src/common.rs +++ b/crates/revm/src/common.rs @@ -1,7 +1,7 @@ -use primitive_types::H256; +use crate::bits::B256; use sha3::{Digest, Keccak256}; #[inline(always)] -pub fn keccak256(input: &[u8]) -> H256 { - H256::from_slice(Keccak256::digest(input).as_ref()) +pub fn keccak256(input: &[u8]) -> B256 { + B256::from_slice(Keccak256::digest(input).as_slice()) } diff --git a/crates/revm/src/db.rs b/crates/revm/src/db.rs index fbcdf97c10..aac22434bf 100644 --- a/crates/revm/src/db.rs +++ b/crates/revm/src/db.rs @@ -5,49 +5,47 @@ pub mod web3db; #[cfg(feature = "web3db")] pub use web3db::Web3DB; -pub use in_memory_db::{AccountState, BenchmarkDB, CacheDB, DbAccount, EmptyDB, InMemoryDB}; - -use crate::{interpreter::bytecode::Bytecode, Account}; -use hashbrown::HashMap as Map; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; - +use crate::bits::{B160, B256}; use crate::AccountInfo; +use crate::U256; +use crate::{interpreter::bytecode::Bytecode, Account}; use auto_impl::auto_impl; +use hashbrown::HashMap as Map; +pub use in_memory_db::{AccountState, BenchmarkDB, CacheDB, DbAccount, EmptyDB, InMemoryDB}; #[auto_impl(& mut, Box)] pub trait Database { type Error; /// Get basic account information. - fn basic(&mut self, address: H160) -> Result, Self::Error>; + fn basic(&mut self, address: B160) -> Result, Self::Error>; /// Get account code by its hash - fn code_by_hash(&mut self, code_hash: H256) -> Result; + fn code_by_hash(&mut self, code_hash: B256) -> Result; /// Get storage value of address at index. - fn storage(&mut self, address: H160, index: U256) -> Result; + fn storage(&mut self, address: B160, index: U256) -> Result; // History related - fn block_hash(&mut self, number: U256) -> Result; + fn block_hash(&mut self, number: U256) -> Result; } #[auto_impl(& mut, Box)] pub trait DatabaseCommit { - fn commit(&mut self, changes: Map); + fn commit(&mut self, changes: Map); } #[auto_impl(&, Box)] pub trait DatabaseRef { type Error; /// Whether account at address exists. - //fn exists(&self, address: H160) -> Option; + //fn exists(&self, address: B160) -> Option; /// Get basic account information. - fn basic(&self, address: H160) -> Result, Self::Error>; + fn basic(&self, address: B160) -> Result, Self::Error>; /// Get account code by its hash - fn code_by_hash(&self, code_hash: H256) -> Result; + fn code_by_hash(&self, code_hash: B256) -> Result; /// Get storage value of address at index. - fn storage(&self, address: H160, index: U256) -> Result; + fn storage(&self, address: B160, index: U256) -> Result; // History related - fn block_hash(&self, number: U256) -> Result; + fn block_hash(&self, number: U256) -> Result; } pub struct RefDBWrapper<'a, Error> { @@ -63,20 +61,20 @@ impl<'a, Error> RefDBWrapper<'a, Error> { impl<'a, Error> Database for RefDBWrapper<'a, Error> { type Error = Error; /// Get basic account information. - fn basic(&mut self, address: H160) -> Result, Self::Error> { + fn basic(&mut self, address: B160) -> Result, Self::Error> { self.db.basic(address) } /// Get account code by its hash - fn code_by_hash(&mut self, code_hash: H256) -> Result { + fn code_by_hash(&mut self, code_hash: B256) -> Result { self.db.code_by_hash(code_hash) } /// Get storage value of address at index. - fn storage(&mut self, address: H160, index: U256) -> Result { + fn storage(&mut self, address: B160, index: U256) -> Result { self.db.storage(address, index) } // History related - fn block_hash(&mut self, number: U256) -> Result { + fn block_hash(&mut self, number: U256) -> Result { self.db.block_hash(number) } } diff --git a/crates/revm/src/db/in_memory_db.rs b/crates/revm/src/db/in_memory_db.rs index 659791df5a..88d8e1b275 100644 --- a/crates/revm/src/db/in_memory_db.rs +++ b/crates/revm/src/db/in_memory_db.rs @@ -2,11 +2,10 @@ use super::{DatabaseCommit, DatabaseRef}; use crate::common::keccak256; use crate::{interpreter::bytecode::Bytecode, Database, KECCAK_EMPTY}; use crate::{Account, AccountInfo, Log}; +use crate::{B160, B256, U256}; use alloc::vec::Vec; use core::convert::Infallible; use hashbrown::{hash_map::Entry, HashMap as Map}; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; pub type InMemoryDB = CacheDB; @@ -21,10 +20,10 @@ impl Default for InMemoryDB { pub struct CacheDB { /// Account info where None means it is not existing. Not existing state is needed for Pre TANGERINE forks. /// `code` is always `None`, and bytecode can be found in `contracts`. - pub accounts: Map, - pub contracts: Map, + pub accounts: Map, + pub contracts: Map, pub logs: Vec, - pub block_hashes: Map, + pub block_hashes: Map, pub db: ExtDB, } @@ -96,7 +95,7 @@ impl CacheDB { pub fn new(db: ExtDB) -> Self { let mut contracts = Map::new(); contracts.insert(KECCAK_EMPTY, Bytecode::new()); - contracts.insert(H256::zero(), Bytecode::new()); + contracts.insert(B256::zero(), Bytecode::new()); Self { accounts: Map::new(), contracts, @@ -115,18 +114,18 @@ impl CacheDB { .or_insert_with(|| code.clone()); } } - if account.code_hash.is_zero() { + if account.code_hash == B256::zero() { account.code_hash = KECCAK_EMPTY; } } /// Insert account info but not override storage - pub fn insert_account_info(&mut self, address: H160, mut info: AccountInfo) { + pub fn insert_account_info(&mut self, address: B160, mut info: AccountInfo) { self.insert_contract(&mut info); self.accounts.entry(address).or_default().info = info; } - fn load_account(&mut self, address: H160) -> Result<&mut DbAccount, ExtDB::Error> { + fn load_account(&mut self, address: B160) -> Result<&mut DbAccount, ExtDB::Error> { let db = &self.db; match self.accounts.entry(address) { Entry::Occupied(entry) => Ok(entry.into_mut()), @@ -144,7 +143,7 @@ impl CacheDB { /// insert account storage without overriding account info pub fn insert_account_storage( &mut self, - address: H160, + address: B160, slot: U256, value: U256, ) -> Result<(), ExtDB::Error> { @@ -156,7 +155,7 @@ impl CacheDB { /// replace account storage without overriding account info pub fn replace_account_storage( &mut self, - address: H160, + address: B160, storage: Map, ) -> Result<(), ExtDB::Error> { let account = self.load_account(address)?; @@ -167,7 +166,7 @@ impl CacheDB { } impl DatabaseCommit for CacheDB { - fn commit(&mut self, changes: Map) { + fn commit(&mut self, changes: Map) { for (address, mut account) in changes { if account.is_destroyed { let db_account = self.accounts.entry(address).or_default(); @@ -200,7 +199,7 @@ impl DatabaseCommit for CacheDB { impl Database for CacheDB { type Error = ExtDB::Error; - fn block_hash(&mut self, number: U256) -> Result { + fn block_hash(&mut self, number: U256) -> Result { match self.block_hashes.entry(number) { Entry::Occupied(entry) => Ok(*entry.get()), Entry::Vacant(entry) => { @@ -211,7 +210,7 @@ impl Database for CacheDB { } } - fn basic(&mut self, address: H160) -> Result, Self::Error> { + fn basic(&mut self, address: B160) -> Result, Self::Error> { let basic = match self.accounts.entry(address) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert( @@ -230,7 +229,7 @@ impl Database for CacheDB { /// Get the value in an account's storage slot. /// /// It is assumed that account is already loaded. - fn storage(&mut self, address: H160, index: U256) -> Result { + fn storage(&mut self, address: B160, index: U256) -> Result { match self.accounts.entry(address) { Entry::Occupied(mut acc_entry) => { let acc_entry = acc_entry.get_mut(); @@ -267,7 +266,7 @@ impl Database for CacheDB { } } - fn code_by_hash(&mut self, code_hash: H256) -> Result { + fn code_by_hash(&mut self, code_hash: B256) -> Result { match self.contracts.entry(code_hash) { Entry::Occupied(entry) => Ok(entry.get().clone()), Entry::Vacant(entry) => { @@ -281,14 +280,14 @@ impl Database for CacheDB { impl DatabaseRef for CacheDB { type Error = ExtDB::Error; - fn basic(&self, address: H160) -> Result, Self::Error> { + fn basic(&self, address: B160) -> Result, Self::Error> { match self.accounts.get(&address) { Some(acc) => Ok(acc.info()), None => self.db.basic(address), } } - fn storage(&self, address: H160, index: U256) -> Result { + fn storage(&self, address: B160, index: U256) -> Result { match self.accounts.get(&address) { Some(acc_entry) => match acc_entry.storage.get(&index) { Some(entry) => Ok(*entry), @@ -307,14 +306,14 @@ impl DatabaseRef for CacheDB { } } - fn code_by_hash(&self, code_hash: H256) -> Result { + fn code_by_hash(&self, code_hash: B256) -> Result { match self.contracts.get(&code_hash) { Some(entry) => Ok(entry.clone()), None => self.db.code_by_hash(code_hash), } } - fn block_hash(&self, number: U256) -> Result { + fn block_hash(&self, number: U256) -> Result { match self.block_hashes.get(&number) { Some(entry) => Ok(*entry), None => self.db.block_hash(number), @@ -329,20 +328,20 @@ pub struct EmptyDB(); impl DatabaseRef for EmptyDB { type Error = Infallible; /// Get basic account information. - fn basic(&self, _address: H160) -> Result, Self::Error> { + fn basic(&self, _address: B160) -> Result, Self::Error> { Ok(None) } /// Get account code by its hash - fn code_by_hash(&self, _code_hash: H256) -> Result { + fn code_by_hash(&self, _code_hash: B256) -> Result { Ok(Bytecode::new()) } /// Get storage value of address at index. - fn storage(&self, _address: H160, _index: U256) -> Result { + fn storage(&self, _address: B160, _index: U256) -> Result { Ok(U256::default()) } // History related - fn block_hash(&self, number: U256) -> Result { + fn block_hash(&self, number: U256) -> Result { Ok(keccak256(&number.to_be_bytes::<{ U256::BYTES }>())) } } @@ -351,7 +350,7 @@ impl DatabaseRef for EmptyDB { /// /// Any other address will return an empty account. #[derive(Debug, Default, Clone)] -pub struct BenchmarkDB(pub Bytecode, H256); +pub struct BenchmarkDB(pub Bytecode, B256); impl BenchmarkDB { pub fn new_bytecode(bytecode: Bytecode) -> Self { @@ -363,8 +362,8 @@ impl BenchmarkDB { impl Database for BenchmarkDB { type Error = Infallible; /// Get basic account information. - fn basic(&mut self, address: H160) -> Result, Self::Error> { - if address == H160::zero() { + fn basic(&mut self, address: B160) -> Result, Self::Error> { + if address == B160::zero() { return Ok(Some(AccountInfo { nonce: 1, balance: U256::from(10000000), @@ -376,33 +375,30 @@ impl Database for BenchmarkDB { } /// Get account code by its hash - fn code_by_hash(&mut self, _code_hash: H256) -> Result { + fn code_by_hash(&mut self, _code_hash: B256) -> Result { Ok(Bytecode::default()) } /// Get storage value of address at index. - fn storage(&mut self, _address: H160, _index: U256) -> Result { + fn storage(&mut self, _address: B160, _index: U256) -> Result { Ok(U256::default()) } // History related - fn block_hash(&mut self, _number: U256) -> Result { - Ok(H256::default()) + fn block_hash(&mut self, _number: U256) -> Result { + Ok(B256::default()) } } #[cfg(test)] mod tests { - use primitive_types::H160; - use ruint::aliases::U256; - - use crate::{AccountInfo, Database}; - use super::{CacheDB, EmptyDB}; + use crate::{AccountInfo, Database}; + use ruint::aliases::U256; #[test] pub fn test_insert_account_storage() { - let account = H160::from_low_u64_be(42); + let account = 42.into(); let nonce = 42; let mut init_state = CacheDB::new(EmptyDB::default()); init_state.insert_account_info( @@ -423,7 +419,7 @@ mod tests { #[test] pub fn test_replace_account_storage() { - let account = H160::from_low_u64_be(42); + let account = 42.into(); let nonce = 42; let mut init_state = CacheDB::new(EmptyDB::default()); init_state.insert_account_info( diff --git a/crates/revm/src/db/web3db.rs b/crates/revm/src/db/web3db.rs index d3c5d8c700..bc1ad1f2e9 100644 --- a/crates/revm/src/db/web3db.rs +++ b/crates/revm/src/db/web3db.rs @@ -1,7 +1,7 @@ -use crate::{interpreter::bytecode::Bytecode, AccountInfo, Database, KECCAK_EMPTY}; +use crate::{ + interpreter::bytecode::Bytecode, AccountInfo, Database, B160, B256, KECCAK_EMPTY, U256, +}; use bytes::Bytes; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; use tokio::runtime::{Handle, Runtime}; use web3::{ transports::Http, @@ -51,8 +51,8 @@ impl Web3DB { impl Database for Web3DB { type Error = (); - fn basic(&mut self, address: H160) -> Result, Self::Error> { - let add = wH160(address.0); + fn basic(&mut self, address: B160) -> Result, Self::Error> { + let add = wH160::from(address.0); let f = async { let nonce = self.web3.eth().transaction_count(add, self.block_number); let balance = self.web3.eth().balance(add, self.block_number); @@ -77,18 +77,14 @@ impl Database for Web3DB { ))) } - fn code_by_hash(&mut self, _code_hash: primitive_types::H256) -> Result { + fn code_by_hash(&mut self, _code_hash: B256) -> Result { panic!("Should not be called. Code is already loaded"); // not needed because we already load code with basic info } - fn storage( - &mut self, - address: primitive_types::H160, - index: U256, - ) -> Result { - let add = wH160(address.0); - let index = wU256(index.into_limbs()); + fn storage(&mut self, address: B160, index: U256) -> Result { + let add = wH160::from(address.0); + let index = wU256(*index.as_limbs()); let f = async { let storage = self .web3 @@ -101,7 +97,7 @@ impl Database for Web3DB { Ok(self.block_on(f)) } - fn block_hash(&mut self, number: U256) -> Result { + fn block_hash(&mut self, number: U256) -> Result { if number > U256::from(u64::MAX) { return Ok(KECCAK_EMPTY); } @@ -114,6 +110,6 @@ impl Database for Web3DB { .ok() .flatten() }; - Ok(H256(self.block_on(f).unwrap().hash.unwrap().0)) + Ok(B256(self.block_on(f).unwrap().hash.unwrap().0)) } } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index c0cd1932e4..43df9c4e2e 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1,4 +1,5 @@ use crate::{ + bits::{B160, B256}, common::keccak256, db::Database, gas, @@ -9,15 +10,13 @@ use crate::{ precompiles, return_ok, return_revert, AnalysisKind, CallContext, CallInputs, CallScheme, CreateInputs, CreateScheme, Env, ExecutionResult, Gas, Inspector, Log, Return, Spec, SpecId::{self, *}, - TransactOut, TransactTo, Transfer, KECCAK_EMPTY, + TransactOut, TransactTo, Transfer, KECCAK_EMPTY, U256, }; use alloc::vec::Vec; use bytes::Bytes; use core::{cmp::min, marker::PhantomData}; use hashbrown::HashMap as Map; -use primitive_types::{H160, H256}; -use revm_precompiles::{Precompile, PrecompileOutput, Precompiles}; -use ruint::aliases::U256; +use revm_precompiles::{Precompile, Precompiles}; pub struct EVMData<'a, DB: Database> { pub env: &'a mut Env, @@ -239,9 +238,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, fn finalize( &mut self, - caller: H160, + caller: B160, gas: &Gas, - ) -> (Map, Vec, u64, u64) { + ) -> (Map, Vec, u64, u64) { let coinbase = self.data.env.block.coinbase; let (gas_used, gas_refunded) = if crate::USE_GAS { let effective_gas_price = self.data.env.effective_gas_price(); @@ -305,12 +304,13 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, // will have sum. if self.data.env.cfg.perf_all_precompiles_have_balance { for address in self.precompiles.addresses() { - if let Some(precompile) = new_state.get_mut(address) { + let address = B160(*address); + if let Some(precompile) = new_state.get_mut(&address) { // we found it. precompile.info.balance += self .data .db - .basic(*address) + .basic(address) .ok() .flatten() .map(|acc| acc.balance) @@ -381,7 +381,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, fn create_inner( &mut self, inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { // Call inspector if INSPECT { let (ret, address, gas, out) = self.inspector.create(&mut self.data, inputs); @@ -640,29 +640,25 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, Precompile::Custom(fun) => fun(inputs.input.as_ref(), inputs.gas_limit), }; match out { - Ok(PrecompileOutput { output, cost, logs }) => { - if !crate::USE_GAS || gas.record_cost(cost) { - logs.into_iter().for_each(|l| { - self.data.journaled_state.log(Log { - address: l.address, - topics: l.topics, - data: l.data, - }) - }); + Ok((gas_used, data)) => { + if !crate::USE_GAS || gas.record_cost(gas_used) { self.data.journaled_state.checkpoint_commit(); - (Return::Continue, gas, Bytes::from(output)) + (Return::Continue, gas, Bytes::from(data)) } else { self.data.journaled_state.checkpoint_revert(checkpoint); (Return::OutOfGas, gas, Bytes::new()) } } Err(e) => { - let ret = if let precompiles::Return::OutOfGas = e { + let ret = if let precompiles::Error::OutOfGas = e { Return::OutOfGas } else { + // TODO Consider using precompile errors. + // This would make Return be a litlle bit fatter, but with removal + // of return in instruction this shouldn't be a problem. Return::PrecompileError }; - self.data.journaled_state.checkpoint_revert(checkpoint); //TODO check if we are discarding or reverting + self.data.journaled_state.checkpoint_revert(checkpoint); (ret, gas, Bytes::new()) } } @@ -724,7 +720,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host self.data.env } - fn block_hash(&mut self, number: U256) -> Option { + fn block_hash(&mut self, number: U256) -> Option { self.data .db .block_hash(number) @@ -732,7 +728,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .ok() } - fn load_account(&mut self, address: H160) -> Option<(bool, bool)> { + fn load_account(&mut self, address: B160) -> Option<(bool, bool)> { self.data .journaled_state .load_account_exist(address, self.data.db) @@ -740,7 +736,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .ok() } - fn balance(&mut self, address: H160) -> Option<(U256, bool)> { + fn balance(&mut self, address: B160) -> Option<(U256, bool)> { let db = &mut self.data.db; let journal = &mut self.data.journaled_state; let error = &mut self.data.error; @@ -751,7 +747,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .map(|(acc, is_cold)| (acc.info.balance, is_cold)) } - fn code(&mut self, address: H160) -> Option<(Bytecode, bool)> { + fn code(&mut self, address: B160) -> Option<(Bytecode, bool)> { let journal = &mut self.data.journaled_state; let db = &mut self.data.db; let error = &mut self.data.error; @@ -764,7 +760,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } /// Get code hash of address. - fn code_hash(&mut self, address: H160) -> Option<(H256, bool)> { + fn code_hash(&mut self, address: B160) -> Option<(B256, bool)> { let journal = &mut self.data.journaled_state; let db = &mut self.data.db; let error = &mut self.data.error; @@ -780,13 +776,13 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } if acc.is_empty() { // TODO check this for pre tangerine fork - return Some((H256::zero(), is_cold)); + return Some((B256::zero(), is_cold)); } Some((acc.info.code_hash, is_cold)) } - fn sload(&mut self, address: H160, index: U256) -> Option<(U256, bool)> { + fn sload(&mut self, address: B160, index: U256) -> Option<(U256, bool)> { // account is always hot. reference on that statement https://eips.ethereum.org/EIPS/eip-2929 see `Note 2:` self.data .journaled_state @@ -797,7 +793,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host fn sstore( &mut self, - address: H160, + address: B160, index: U256, value: U256, ) -> Option<(U256, U256, U256, bool)> { @@ -808,7 +804,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .ok() } - fn log(&mut self, address: H160, topics: Vec, data: Bytes) { + fn log(&mut self, address: B160, topics: Vec, data: Bytes) { if INSPECT { self.inspector.log(&mut self.data, &address, &topics, &data); } @@ -820,7 +816,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host self.data.journaled_state.log(log); } - fn selfdestruct(&mut self, address: H160, target: H160) -> Option { + fn selfdestruct(&mut self, address: B160, target: B160) -> Option { if INSPECT { self.inspector.selfdestruct(); } @@ -834,7 +830,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host fn create( &mut self, inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { self.create_inner::(inputs) } @@ -844,17 +840,16 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } /// Returns the address for the legacy `CREATE` scheme: [`CreateScheme::Create`] -pub fn create_address(caller: H160, nonce: u64) -> H160 { +pub fn create_address(caller: B160, nonce: u64) -> B160 { let mut stream = rlp::RlpStream::new_list(2); - stream.append(&caller); + stream.append(&caller.0.as_ref()); stream.append(&nonce); let out = keccak256(&stream.out()); - let out = H160::from_slice(&out.as_bytes()[12..]); - out + B160(out[12..].try_into().unwrap()) } /// Returns the address for the `CREATE2` scheme: [`CreateScheme::Create2`] -pub fn create2_address(caller: H160, code_hash: H256, salt: U256) -> H160 { +pub fn create2_address(caller: B160, code_hash: B256, salt: U256) -> B160 { use sha3::{Digest, Keccak256}; let mut hasher = Keccak256::new(); hasher.update([0xff]); @@ -862,7 +857,7 @@ pub fn create2_address(caller: H160, code_hash: H256, salt: U256) -> H160 { hasher.update(salt.to_be_bytes::<{ U256::BYTES }>()); hasher.update(&code_hash[..]); - H160::from_slice(&hasher.finalize().as_slice()[12..]) + B160(hasher.finalize().as_slice()[12..].try_into().unwrap()) } /// EVM context host. @@ -877,33 +872,33 @@ pub trait Host { fn env(&mut self) -> &mut Env; /// load account. Returns (is_cold,is_new_account) - fn load_account(&mut self, address: H160) -> Option<(bool, bool)>; + fn load_account(&mut self, address: B160) -> Option<(bool, bool)>; /// Get environmental block hash. - fn block_hash(&mut self, number: U256) -> Option; + fn block_hash(&mut self, number: U256) -> Option; /// Get balance of address. - fn balance(&mut self, address: H160) -> Option<(U256, bool)>; + fn balance(&mut self, address: B160) -> Option<(U256, bool)>; /// Get code of address. - fn code(&mut self, address: H160) -> Option<(Bytecode, bool)>; + fn code(&mut self, address: B160) -> Option<(Bytecode, bool)>; /// Get code hash of address. - fn code_hash(&mut self, address: H160) -> Option<(H256, bool)>; + fn code_hash(&mut self, address: B160) -> Option<(B256, bool)>; /// Get storage value of address at index. - fn sload(&mut self, address: H160, index: U256) -> Option<(U256, bool)>; + fn sload(&mut self, address: B160, index: U256) -> Option<(U256, bool)>; /// Set storage value of address at index. Return if slot is cold/hot access. fn sstore( &mut self, - address: H160, + address: B160, index: U256, value: U256, ) -> Option<(U256, U256, U256, bool)>; /// Create a log owned by address with given topics and data. - fn log(&mut self, address: H160, topics: Vec, data: Bytes); + fn log(&mut self, address: B160, topics: Vec, data: Bytes); /// Mark an address to be deleted, with funds transferred to target. - fn selfdestruct(&mut self, address: H160, target: H160) -> Option; + fn selfdestruct(&mut self, address: B160, target: B160) -> Option; /// Invoke a create operation. fn create( &mut self, inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes); + ) -> (Return, Option, Gas, Bytes); /// Invoke a call operation. fn call(&mut self, input: &mut CallInputs) -> (Return, Gas, Bytes); } diff --git a/crates/revm/src/gas/calc.rs b/crates/revm/src/gas/calc.rs index 5a3df2908e..f4c601eb44 100644 --- a/crates/revm/src/gas/calc.rs +++ b/crates/revm/src/gas/calc.rs @@ -1,6 +1,5 @@ use super::constants::*; -use crate::{models::SelfDestructResult, Spec, SpecId::*}; -use ruint::aliases::U256; +use crate::{models::SelfDestructResult, Spec, SpecId::*, U256}; #[allow(clippy::collapsible_else_if)] pub fn sstore_refund(original: U256, current: U256, new: U256) -> i64 { diff --git a/crates/revm/src/inspector.rs b/crates/revm/src/inspector.rs index 33ac2adf22..9b85db0975 100644 --- a/crates/revm/src/inspector.rs +++ b/crates/revm/src/inspector.rs @@ -1,11 +1,10 @@ -use bytes::Bytes; -use primitive_types::{H160, H256}; - use crate::{ - evm_impl::EVMData, opcode, spec_opcode_gas, CallInputs, CreateInputs, Database, Gas, - Interpreter, Return, + bits::{B160, B256}, + evm_impl::EVMData, + opcode, spec_opcode_gas, CallInputs, CreateInputs, Database, Gas, Interpreter, Return, }; use auto_impl::auto_impl; +use bytes::Bytes; #[auto_impl(&mut, Box)] pub trait Inspector { @@ -43,8 +42,8 @@ pub trait Inspector { fn log( &mut self, _evm_data: &mut EVMData<'_, DB>, - _address: &H160, - _topics: &[H256], + _address: &B160, + _topics: &[B256], _data: &Bytes, ) { } @@ -97,7 +96,7 @@ pub trait Inspector { &mut self, _data: &mut EVMData<'_, DB>, _inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { (Return::Continue, None, Gas::new(0), Bytes::default()) } @@ -110,10 +109,10 @@ pub trait Inspector { _data: &mut EVMData<'_, DB>, _inputs: &CreateInputs, ret: Return, - address: Option, + address: Option, remaining_gas: Gas, out: Bytes, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { (ret, address, remaining_gas, out) } @@ -230,10 +229,10 @@ impl Inspector for GasInspector { _data: &mut EVMData<'_, DB>, _inputs: &CreateInputs, ret: Return, - address: Option, + address: Option, remaining_gas: Gas, out: Bytes, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { self.was_return = true; (ret, address, remaining_gas, out) } @@ -244,11 +243,10 @@ mod tests { use crate::db::BenchmarkDB; use crate::{ opcode, Bytecode, CallInputs, CreateInputs, Database, EVMData, Gas, GasInspector, - Inspector, Interpreter, OpCode, Return, TransactTo, + Inspector, Interpreter, OpCode, Return, TransactTo, B160, B256, }; use bytes::Bytes; - use core::str::FromStr; - use primitive_types::{H160, H256}; + use hex_literal::hex; #[derive(Default, Debug)] struct StackInspector { @@ -283,8 +281,8 @@ mod tests { fn log( &mut self, evm_data: &mut EVMData<'_, DB>, - address: &H160, - topics: &[H256], + address: &B160, + topics: &[B256], data: &Bytes, ) { self.gas_inspector.log(evm_data, address, topics, data); @@ -332,7 +330,7 @@ mod tests { &mut self, data: &mut EVMData<'_, DB>, call: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { self.gas_inspector.create(data, call); ( @@ -348,10 +346,10 @@ mod tests { data: &mut EVMData<'_, DB>, inputs: &CreateInputs, status: Return, - address: Option, + address: Option, gas: Gas, retdata: Bytes, - ) -> (Return, Option, Gas, Bytes) { + ) -> (Return, Option, Gas, Bytes) { self.gas_inspector .create_end(data, inputs, status, address, gas, retdata.clone()); (status, address, gas, retdata) @@ -379,9 +377,9 @@ mod tests { let mut evm = crate::new(); evm.database(BenchmarkDB::new_bytecode(bytecode.clone())); - evm.env.tx.caller = H160::from_str("0x1000000000000000000000000000000000000000").unwrap(); + evm.env.tx.caller = B160(hex!("1000000000000000000000000000000000000000")); evm.env.tx.transact_to = - TransactTo::Call(H160::from_str("0x0000000000000000000000000000000000000000").unwrap()); + TransactTo::Call(B160(hex!("0000000000000000000000000000000000000000"))); evm.env.tx.gas_limit = 21100; let mut inspector = StackInspector::default(); diff --git a/crates/revm/src/instructions.rs b/crates/revm/src/instructions.rs index 54f0da6740..faaaa0fb75 100644 --- a/crates/revm/src/instructions.rs +++ b/crates/revm/src/instructions.rs @@ -13,9 +13,8 @@ mod system; pub use opcode::{OpCode, OPCODE_JUMPMAP}; -use crate::{interpreter::Interpreter, CallScheme, Host, Spec, SpecId::*}; +use crate::{interpreter::Interpreter, CallScheme, Host, Spec, SpecId::*, U256}; use core::ops::{BitAnd, BitOr, BitXor}; -use ruint::aliases::U256; #[macro_export] macro_rules! return_ok { diff --git a/crates/revm/src/instructions/arithmetic.rs b/crates/revm/src/instructions/arithmetic.rs index ebb7a43f3a..e05bbdcee6 100644 --- a/crates/revm/src/instructions/arithmetic.rs +++ b/crates/revm/src/instructions/arithmetic.rs @@ -1,7 +1,5 @@ -use crate::{gas, Interpreter, Return, Spec}; - use super::i256::{i256_div, i256_mod}; -use ruint::aliases::U256; +use crate::{gas, Interpreter, Return, Spec, U256}; pub fn div(op1: U256, op2: U256) -> U256 { op1.checked_div(op2).unwrap_or_default() diff --git a/crates/revm/src/instructions/bitwise.rs b/crates/revm/src/instructions/bitwise.rs index d7a9e19c8d..4bca936ed2 100644 --- a/crates/revm/src/instructions/bitwise.rs +++ b/crates/revm/src/instructions/bitwise.rs @@ -1,7 +1,6 @@ -use core::cmp::Ordering; - use super::i256::{i256_cmp, i256_sign, two_compl, Sign}; -use ruint::aliases::U256; +use crate::U256; +use core::cmp::Ordering; pub fn slt(op1: U256, op2: U256) -> U256 { if i256_cmp(op1, op2) == Ordering::Less { diff --git a/crates/revm/src/instructions/control.rs b/crates/revm/src/instructions/control.rs index ed24c0fde4..1f4e206b7b 100644 --- a/crates/revm/src/instructions/control.rs +++ b/crates/revm/src/instructions/control.rs @@ -1,5 +1,4 @@ -use crate::{gas, interpreter::Interpreter, Return, Spec, SpecId::*}; -use ruint::aliases::U256; +use crate::{gas, interpreter::Interpreter, Return, Spec, SpecId::*, U256}; pub fn jump(interp: &mut Interpreter) -> Return { // gas!(interp, gas::MID); diff --git a/crates/revm/src/instructions/host.rs b/crates/revm/src/instructions/host.rs index 4f482ee6f8..f856756af7 100644 --- a/crates/revm/src/instructions/host.rs +++ b/crates/revm/src/instructions/host.rs @@ -1,16 +1,15 @@ use crate::{ alloc::vec::Vec, + bits::{B160, B256}, gas::{self, COLD_ACCOUNT_ACCESS_COST, WARM_STORAGE_READ_COST}, interpreter::Interpreter, return_ok, return_revert, CallContext, CallInputs, CallScheme, CreateInputs, CreateScheme, Host, Return, Spec, SpecId::*, - Transfer, + Transfer, U256, }; use bytes::Bytes; use core::cmp::min; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; pub fn balance(interp: &mut Interpreter, host: &mut H) -> Return { pop_address!(interp, address); @@ -78,7 +77,7 @@ pub fn extcodehash(interp: &mut Interpreter, host: &mut H) // WARM_STORAGE_READ_COST is already calculated in gas block gas!(interp, COLD_ACCOUNT_ACCESS_COST - WARM_STORAGE_READ_COST); } - push_h256!(interp, code_hash); + push_b256!(interp, code_hash); Return::Continue } @@ -121,7 +120,7 @@ pub fn blockhash(interp: &mut Interpreter, host: &mut H) -> Return { if ret.is_none() { return Return::FatalExternalError; } - *number = U256::from_be_bytes(ret.unwrap().0); + *number = U256::from_be_bytes(*ret.unwrap()); return Return::Continue; } } @@ -180,7 +179,7 @@ pub fn log(interp: &mut Interpreter, n: u8, host: &mut H) - let mut topics = Vec::with_capacity(n); for _ in 0..(n) { // Safety: stack bounds already checked few lines above - topics.push(unsafe { interp.stack.pop_unsafe() }.to_be_bytes().into()); + topics.push(B256(unsafe { interp.stack.pop_unsafe().to_be_bytes() })); } host.log(interp.contract.address, topics, data); @@ -261,17 +260,17 @@ pub fn create( match return_reason { return_ok!() => { - push_h256!(interp, address.map(|a| a.into()).unwrap_or_default()); + push_b256!(interp, address.unwrap_or_default().into()); interp.gas.erase_cost(gas.remaining()); interp.gas.record_refund(gas.refunded()); } return_revert!() => { - push_h256!(interp, H256::default()); + push_b256!(interp, B256::zero()); interp.gas.erase_cost(gas.remaining()); } Return::FatalExternalError => return Return::FatalExternalError, _ => { - push_h256!(interp, H256::default()); + push_b256!(interp, B256::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 index 904b788041..0acccb7d06 100644 --- a/crates/revm/src/instructions/host_env.rs +++ b/crates/revm/src/instructions/host_env.rs @@ -1,5 +1,4 @@ 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); @@ -11,7 +10,7 @@ pub fn chainid(interp: &mut Interpreter, host: &mut H) -> R pub fn coinbase(interp: &mut Interpreter, host: &mut H) -> Return { // gas!(interp, gas::BASE); - push_h256!(interp, host.env().block.coinbase.into()); + push_b256!(interp, host.env().block.coinbase.into()); Return::Continue } @@ -30,7 +29,7 @@ pub fn number(interp: &mut Interpreter, host: &mut H) -> Return { pub fn difficulty(interp: &mut Interpreter, host: &mut H) -> Return { // gas!(interp, gas::BASE); if SPEC::enabled(MERGE) { - push_h256!(interp, host.env().block.prevrandao.unwrap()); + push_b256!(interp, host.env().block.prevrandao.unwrap()); } else { push!(interp, host.env().block.difficulty); } @@ -59,7 +58,6 @@ pub fn basefee(interp: &mut Interpreter, host: &mut H) -> R 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); + push_b256!(interp, host.env().tx.caller.into()); Return::Continue } diff --git a/crates/revm/src/instructions/i256.rs b/crates/revm/src/instructions/i256.rs index be4adedd42..f374763a16 100644 --- a/crates/revm/src/instructions/i256.rs +++ b/crates/revm/src/instructions/i256.rs @@ -1,5 +1,5 @@ +use crate::U256; use core::cmp::Ordering; -use ruint::aliases::U256; use ruint::uint; #[derive(Copy, Clone, Eq, PartialEq, Debug)] @@ -124,8 +124,8 @@ pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { #[cfg(test)] mod tests { use super::*; + use crate::U256; use core::num::Wrapping; - use ruint::aliases::U256; #[test] fn div_i256() { diff --git a/crates/revm/src/instructions/macros.rs b/crates/revm/src/instructions/macros.rs index 0512222153..43d043721f 100644 --- a/crates/revm/src/instructions/macros.rs +++ b/crates/revm/src/instructions/macros.rs @@ -70,8 +70,10 @@ macro_rules! pop_address { return Return::StackUnderflow; } // Safety: Length is checked above. - let $x1: H160 = H160::from_slice( - &unsafe { $interp.stack.pop_unsafe() }.to_be_bytes::<{ U256::BYTES }>()[12..], + let $x1: B160 = B160( + unsafe { $interp.stack.pop_unsafe() }.to_be_bytes::<{ U256::BYTES }>()[12..] + .try_into() + .unwrap(), ); }; ( $interp:expr, $x1:ident, $x2:ident) => { @@ -79,27 +81,17 @@ macro_rules! pop_address { return Return::StackUnderflow; } let mut temp = H256::zero(); - $x1: H160 = { - // Safety: Length is checked above. - unsafe { - $interp - .stack - .pop_unsafe() - .to_big_endian(temp.as_bytes_mut()) - }; - temp.into() - }; - $x2: H160 = { - temp = H256::zero(); - // Safety: Length is checked above. - unsafe { - $interp - .stack - .pop_unsafe() - .to_big_endian(temp.as_bytes_mut()) - }; - temp.into(); - }; + + let $x1: B160 = B160( + unsafe { $interp.stack.pop_unsafe() }.to_be_bytes::<{ U256::BYTES }>()[12..] + .try_into() + .unwrap(), + ); + let $x2: B160 = B160( + unsafe { $interp.stack.pop_unsafe() }.to_be_bytes::<{ U256::BYTES }>()[12..] + .try_into() + .unwrap(), + ); }; } @@ -159,10 +151,10 @@ macro_rules! pop_top { }; } -macro_rules! push_h256 { +macro_rules! push_b256 { ( $interp:expr, $( $x:expr ),* ) => ( $( - match $interp.stack.push_h256($x) { + match $interp.stack.push_b256($x) { Ok(()) => (), Err(e) => return e, } diff --git a/crates/revm/src/instructions/memory.rs b/crates/revm/src/instructions/memory.rs index 452ba09e79..79541c406b 100644 --- a/crates/revm/src/instructions/memory.rs +++ b/crates/revm/src/instructions/memory.rs @@ -1,5 +1,4 @@ -use crate::{interpreter::Interpreter, Return}; -use ruint::aliases::U256; +use crate::{interpreter::Interpreter, Return, U256}; pub fn mload(interp: &mut Interpreter) -> Return { // gas!(interp, gas::VERYLOW); diff --git a/crates/revm/src/instructions/system.rs b/crates/revm/src/instructions/system.rs index 9335da32d2..22f40dd691 100644 --- a/crates/revm/src/instructions/system.rs +++ b/crates/revm/src/instructions/system.rs @@ -1,15 +1,14 @@ use crate::{ - common::keccak256, gas, interpreter::Interpreter, Return, Spec, SpecId::*, KECCAK_EMPTY, + bits::B256, common::keccak256, gas, interpreter::Interpreter, Return, Spec, SpecId::*, + KECCAK_EMPTY, U256, }; -use primitive_types::H256; -use ruint::aliases::U256; use std::cmp::min; pub fn sha3(interp: &mut Interpreter) -> Return { pop!(interp, from, len); let len = as_usize_or_fail!(len, Return::OutOfGas); gas_or_fail!(interp, gas::sha3_cost(len as u64)); - let h256 = if len == 0 { + let hash = if len == 0 { KECCAK_EMPTY } else { let from = as_usize_or_fail!(from, Return::OutOfGas); @@ -17,28 +16,25 @@ pub fn sha3(interp: &mut Interpreter) -> Return { keccak256(interp.memory.get_slice(from, len)) }; - push_h256!(interp, h256); + push_b256!(interp, hash); Return::Continue } pub fn address(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); - let ret = H256::from(interp.contract.address); - push_h256!(interp, ret); + push_b256!(interp, B256::from(interp.contract.address)); Return::Continue } pub fn caller(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); - let ret = H256::from(interp.contract.caller); - push_h256!(interp, ret); + push_b256!(interp, B256::from(interp.contract.caller)); Return::Continue } pub fn codesize(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); - let size = U256::from(interp.contract.bytecode.len()); - push!(interp, size); + push!(interp, U256::from(interp.contract.bytecode.len())); Return::Continue } @@ -69,28 +65,27 @@ pub fn calldataload(interp: &mut Interpreter) -> Return { let index = as_usize_saturated!(index); let load = if index < interp.contract.input.len() { - let mut load = H256::zero(); let have_bytes = min(interp.contract.input.len() - index, 32); - load.0[..have_bytes].copy_from_slice(&interp.contract.input[index..index + have_bytes]); - load + let mut bytes = [0u8; U256::BYTES]; + bytes[..have_bytes].copy_from_slice(&interp.contract.input[index..index + have_bytes]); + B256(bytes) } else { - H256::zero() + B256::zero() }; - push_h256!(interp, load); + push_b256!(interp, load); Return::Continue } pub fn calldatasize(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); - let len = U256::from(interp.contract.input.len()); - push!(interp, len); + push!(interp, U256::from(interp.contract.input.len())); Return::Continue } pub fn callvalue(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); - push_h256!(interp, interp.contract.value.to_be_bytes().into()); + push!(interp, interp.contract.value); Return::Continue } @@ -116,8 +111,7 @@ pub fn returndatasize(interp: &mut Interpreter) -> Return { // gas!(interp, gas::BASE); // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY check!(SPEC::enabled(BYZANTIUM)); - let size = U256::from(interp.return_data_buffer.len()); - push!(interp, size); + push!(interp, U256::from(interp.return_data_buffer.len())); Return::Continue } diff --git a/crates/revm/src/interpreter/bytecode.rs b/crates/revm/src/interpreter/bytecode.rs index a490830fcd..573252726e 100644 --- a/crates/revm/src/interpreter/bytecode.rs +++ b/crates/revm/src/interpreter/bytecode.rs @@ -1,7 +1,6 @@ use super::contract::{AnalysisData, ValidJumpAddress}; -use crate::{common::keccak256, opcode, spec_opcode_gas, Spec, KECCAK_EMPTY}; +use crate::{common::keccak256, opcode, spec_opcode_gas, Spec, B256, KECCAK_EMPTY}; use bytes::Bytes; -use primitive_types::H256; use std::sync::Arc; #[derive(Clone, Debug, Eq, PartialEq)] @@ -22,7 +21,7 @@ pub enum BytecodeState { pub struct Bytecode { #[cfg_attr(feature = "with-serde", serde(with = "crate::models::serde_hex_bytes"))] bytecode: Bytes, - hash: H256, + hash: B256, state: BytecodeState, } @@ -62,7 +61,7 @@ impl Bytecode { /// /// # Safety /// Hash need to be appropriate keccak256 over bytecode. - pub unsafe fn new_raw_with_hash(bytecode: Bytes, hash: H256) -> Self { + pub unsafe fn new_raw_with_hash(bytecode: Bytes, hash: B256) -> Self { Self { bytecode, hash, @@ -75,7 +74,7 @@ impl Bytecode { /// # Safety /// Bytecode need to end with STOP (0x00) opcode as checked bytecode assumes /// that it is safe to iterate over bytecode without checking lengths - pub unsafe fn new_checked(bytecode: Bytes, len: usize, hash: Option) -> Self { + pub unsafe fn new_checked(bytecode: Bytes, len: usize, hash: Option) -> Self { let hash = match hash { None if len == 0 => KECCAK_EMPTY, None => keccak256(&bytecode), @@ -98,7 +97,7 @@ impl Bytecode { bytecode: Bytes, len: usize, jumptable: ValidJumpAddress, - hash: Option, + hash: Option, ) -> Self { let hash = match hash { None if len == 0 => KECCAK_EMPTY, @@ -116,7 +115,7 @@ impl Bytecode { &self.bytecode } - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> B256 { self.hash } @@ -266,7 +265,7 @@ impl Bytecode { pub struct BytecodeLocked { bytecode: Bytes, len: usize, - hash: H256, + hash: B256, jumptable: ValidJumpAddress, } @@ -278,7 +277,7 @@ impl BytecodeLocked { self.len } - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> B256 { self.hash } diff --git a/crates/revm/src/interpreter/contract.rs b/crates/revm/src/interpreter/contract.rs index 87571634cb..35f8a9c7f3 100644 --- a/crates/revm/src/interpreter/contract.rs +++ b/crates/revm/src/interpreter/contract.rs @@ -1,8 +1,6 @@ use super::bytecode::{Bytecode, BytecodeLocked}; -use crate::{alloc::vec::Vec, CallContext, Spec}; +use crate::{alloc::vec::Vec, CallContext, Spec, B160, U256}; use bytes::Bytes; -use primitive_types::H160; -use ruint::aliases::U256; use std::sync::Arc; pub struct Contract { @@ -12,9 +10,9 @@ pub struct Contract { /// Note that current code is extended with push padding and STOP at end. pub bytecode: BytecodeLocked, /// Contract address - pub address: H160, + pub address: B160, /// Caller of the EVM. - pub caller: H160, + pub caller: B160, /// Value send to contract. pub value: U256, } @@ -65,8 +63,8 @@ impl Contract { pub fn new( input: Bytes, bytecode: Bytecode, - address: H160, - caller: H160, + address: B160, + caller: B160, value: U256, ) -> Self { let bytecode = bytecode.lock::(); diff --git a/crates/revm/src/interpreter/memory.rs b/crates/revm/src/interpreter/memory.rs index 591e609780..b63bbe48a8 100644 --- a/crates/revm/src/interpreter/memory.rs +++ b/crates/revm/src/interpreter/memory.rs @@ -1,9 +1,8 @@ -use crate::alloc::vec::Vec; +use crate::{alloc::vec::Vec, U256}; use core::{ cmp::min, ops::{BitAnd, Not}, }; -use ruint::aliases::U256; /// A sequencial memory. It uses Rust's `Vec` for internal /// representation. diff --git a/crates/revm/src/interpreter/stack.rs b/crates/revm/src/interpreter/stack.rs index f2cb466344..3717cfd3fe 100644 --- a/crates/revm/src/interpreter/stack.rs +++ b/crates/revm/src/interpreter/stack.rs @@ -1,6 +1,4 @@ -use crate::{alloc::vec::Vec, Return}; -use primitive_types::H256; -use ruint::aliases::U256; +use crate::{alloc::vec::Vec, Return, B256, U256}; pub const STACK_LIMIT: usize = 1024; @@ -182,7 +180,7 @@ impl Stack { #[inline] /// Push a new value into the stack. If it will exceed the stack limit, /// returns `StackOverflow` error and leaves the stack unchanged. - pub fn push_h256(&mut self, value: H256) -> Result<(), Return> { + pub fn push_b256(&mut self, value: B256) -> Result<(), Return> { if self.data.len() + 1 > STACK_LIMIT { return Err(Return::StackOverflow); } @@ -245,7 +243,7 @@ impl Stack { Return::Continue } - /// push slice onto memory it is expected to be max 32 bytes and be contains inside H256 + /// push slice onto memory it is expected to be max 32 bytes and be contains inside B256 #[inline(always)] pub fn push_slice(&mut self, slice: &[u8]) -> Return { let new_len = self.data.len() + 1; diff --git a/crates/revm/src/journaled_state.rs b/crates/revm/src/journaled_state.rs index ff5cc74691..c89f80e031 100644 --- a/crates/revm/src/journaled_state.rs +++ b/crates/revm/src/journaled_state.rs @@ -2,10 +2,9 @@ use crate::{interpreter::bytecode::Bytecode, models::SelfDestructResult, Return, use alloc::{vec, vec::Vec}; use core::mem::{self}; use hashbrown::{hash_map::Entry, HashMap as Map}; -use primitive_types::H160; use ruint::aliases::U256; -use crate::{db::Database, AccountInfo, Log}; +use crate::{bits::B160, db::Database, AccountInfo, Log}; #[derive(Debug, Clone, Eq, PartialEq)] #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] @@ -27,7 +26,7 @@ pub struct JournaledState { pub num_of_precompiles: usize, } -pub type State = Map; +pub type State = Map; pub type Storage = Map; #[derive(Debug, Clone, Eq, PartialEq)] @@ -113,13 +112,13 @@ pub enum JournalEntry { /// Used to mark account that is hot inside EVM in regards to EIP-2929 AccessList. /// Action: We will add Account to state. /// Revert: we will remove account from state. - AccountLoaded { address: H160 }, + AccountLoaded { address: B160 }, /// Mark account to be destroyed and journal balance to be reverted /// Action: Mark account and transfer the balance /// Revert: Unmark the account and transfer balance back AccountDestroyed { - address: H160, - target: H160, + address: B160, + target: B160, was_destroyed: bool, // if account had already been destroyed before this journal entry had_balance: U256, }, @@ -127,30 +126,30 @@ pub enum JournalEntry { /// Only when account is called (to execute contract or transfer balance) only then account is made touched. /// Action: Mark account touched /// Revert: Unmark account touched - AccountTouched { address: H160 }, + AccountTouched { address: B160 }, /// Transfer balance between two accounts /// Action: Transfer balance /// Revert: Transfer balance back - BalanceTransfer { from: H160, to: H160, balance: U256 }, + BalanceTransfer { from: B160, to: B160, balance: U256 }, /// Increment nonce /// Action: Increment nonce by one /// Revert: Decrement nonce by one NonceChange { - address: H160, //geth has nonce value, + address: B160, //geth has nonce value, }, /// It is used to track both storage change and hot load of storage slot. For hot load in regards /// to EIP-2929 AccessList had_value will be None /// Action: Storage change or hot load /// Revert: Revert to previous value or remove slot from storage StorageChage { - address: H160, + address: B160, key: U256, had_value: Option, //if none, storage slot was cold loaded from db and needs to be removed }, /// Code changed /// Action: Account code changed /// Revert: Revert to previous bytecode. - CodeChange { address: H160, had_code: Bytecode }, + CodeChange { address: B160, had_code: Bytecode }, } /// SubRoutine checkpoint that will help us to go back from this @@ -181,13 +180,13 @@ impl JournaledState { &mut self.state } - pub fn touch(&mut self, address: &H160) { + pub fn touch(&mut self, address: &B160) { if let Some(account) = self.state.get_mut(address) { Self::touch_account(self.journal.last_mut().unwrap(), address, account); } } - fn touch_account(journal: &mut Vec, address: &H160, account: &mut Account) { + fn touch_account(journal: &mut Vec, address: &B160, account: &mut Account) { if !account.is_touched { journal.push(JournalEntry::AccountTouched { address: *address }); account.is_touched = true; @@ -210,7 +209,7 @@ impl JournaledState { } /// Use it with load_account function. - pub fn account(&self, address: H160) -> &Account { + pub fn account(&self, address: B160) -> &Account { self.state.get(&address).unwrap() // Always assume that acc is already loaded } @@ -220,7 +219,7 @@ impl JournaledState { /// use it only if you know that acc is hot /// Assume account is hot - pub fn set_code(&mut self, address: H160, code: Bytecode) { + pub fn set_code(&mut self, address: B160, code: Bytecode) { let account = self.state.get_mut(&address).unwrap(); Self::touch_account(self.journal.last_mut().unwrap(), &address, account); @@ -236,7 +235,7 @@ impl JournaledState { account.info.code = Some(code); } - pub fn inc_nonce(&mut self, address: H160) -> Option { + pub fn inc_nonce(&mut self, address: B160) -> Option { let account = self.state.get_mut(&address).unwrap(); // Check if nonce is going to overflow. if account.info.nonce == u64::MAX { @@ -255,8 +254,8 @@ impl JournaledState { pub fn transfer( &mut self, - from: &H160, - to: &H160, + from: &B160, + to: &B160, balance: U256, db: &mut DB, ) -> Result<(bool, bool), Return> { @@ -299,7 +298,7 @@ impl JournaledState { /// return if it has collision of addresses pub fn create_account( &mut self, - address: H160, + address: B160, is_precompile: bool, db: &mut DB, ) -> Result { @@ -345,8 +344,8 @@ impl JournaledState { journal_entries: Vec, is_spurious_dragon_enabled: bool, ) { - const PRECOMPILE3: H160 = - H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]); + const PRECOMPILE3: B160 = + B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]); for entry in journal_entries.into_iter().rev() { match entry { JournalEntry::AccountLoaded { address } => { @@ -438,8 +437,8 @@ impl JournaledState { /// transfer balance from address to target. Check if target exist/is_cold pub fn selfdestruct( &mut self, - address: H160, - target: H160, + address: B160, + target: B160, db: &mut DB, ) -> Result { let (is_cold, target_exists) = self.load_account_exist(target, db)?; @@ -478,7 +477,7 @@ impl JournaledState { /// load account into memory. return if it is cold or hot accessed pub fn load_account( &mut self, - address: H160, + address: B160, db: &mut DB, ) -> Result<(&mut Account, bool), DB::Error> { Ok(match self.state.entry(address) { @@ -507,7 +506,7 @@ impl JournaledState { // first is is_cold second bool is exists. pub fn load_account_exist( &mut self, - address: H160, + address: B160, db: &mut DB, ) -> Result<(bool, bool), DB::Error> { let is_before_spurious_dragon = self.is_before_spurious_dragon; @@ -523,7 +522,7 @@ impl JournaledState { pub fn load_code( &mut self, - address: H160, + address: B160, db: &mut DB, ) -> Result<(&mut Account, bool), DB::Error> { let (acc, is_cold) = self.load_account(address, db)?; @@ -542,7 +541,7 @@ impl JournaledState { // account is already present and loaded. pub fn sload( &mut self, - address: H160, + address: B160, key: U256, db: &mut DB, ) -> Result<(U256, bool), DB::Error> { @@ -578,7 +577,7 @@ impl JournaledState { /// returns (original,present,new) slot pub fn sstore( &mut self, - address: H160, + address: B160, key: U256, new: U256, db: &mut DB, @@ -614,7 +613,7 @@ impl JournaledState { } } -fn is_precompile(address: H160, num_of_precompiles: usize) -> bool { +fn is_precompile(address: B160, num_of_precompiles: usize) -> bool { if !address[..18].iter().all(|i| *i == 0) { return false; } @@ -630,7 +629,7 @@ mod test { fn test_is_precompile() { assert!( !is_precompile( - H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 3 ), "Zero is not precompile" @@ -638,7 +637,7 @@ mod test { assert!( !is_precompile( - H160([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9]), + B160([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9]), 3 ), "0x100..0 is not precompile" @@ -646,7 +645,7 @@ mod test { assert!( !is_precompile( - H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]), + B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]), 3 ), "0x000..4 is not precompile" @@ -654,7 +653,7 @@ mod test { assert!( is_precompile( - H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), 3 ), "0x00..01 is precompile" @@ -662,7 +661,7 @@ mod test { assert!( is_precompile( - H160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]), + B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]), 3 ), "0x000..3 is precompile" diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index d9cedcb4de..bc269cec87 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] //#![no_std] +pub mod bits; pub mod common; pub mod db; mod evm; @@ -13,6 +14,9 @@ mod journaled_state; mod models; mod specification; +pub use bits::{B160, B256}; +pub use ruint::aliases::U256; + pub use evm_impl::{create2_address, create_address, EVMData, Host}; pub type DummyStateDB = InMemoryDB; diff --git a/crates/revm/src/models.rs b/crates/revm/src/models.rs index 95dc912f18..dc91c63a1d 100644 --- a/crates/revm/src/models.rs +++ b/crates/revm/src/models.rs @@ -1,14 +1,17 @@ use core::cmp::min; -use crate::{alloc::vec::Vec, interpreter::bytecode::Bytecode, Return, SpecId}; +use crate::{ + alloc::vec::Vec, + bits::{B160, B256}, + interpreter::bytecode::Bytecode, + Return, SpecId, U256, +}; use bytes::Bytes; -use primitive_types::{H160, H256}; -use ruint::aliases::U256; +use hex_literal::hex; -pub const KECCAK_EMPTY: H256 = H256([ - 0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, - 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70, -]); +pub const KECCAK_EMPTY: B256 = B256(hex!( + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" +)); /// AccountInfo account information. #[derive(Clone, Debug, Eq)] @@ -19,7 +22,7 @@ pub struct AccountInfo { /// Account nonce. pub nonce: u64, /// code hash, - pub code_hash: H256, + pub code_hash: B256, /// code: if None, `code_by_hash` will be used to fetch it if code needs to be loaded from /// inside of revm. pub code: Option, @@ -56,7 +59,7 @@ impl AccountInfo { } pub fn is_empty(&self) -> bool { - let code_empty = self.code_hash == KECCAK_EMPTY || self.code_hash.is_zero(); + let code_empty = self.code_hash == KECCAK_EMPTY || self.code_hash == B256::zero(); self.balance == U256::ZERO && self.nonce == 0 && code_empty } @@ -76,7 +79,7 @@ impl AccountInfo { #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct CallInputs { /// The target of the call. - pub contract: H160, + pub contract: B160, /// The transfer, if any, in this call. pub transfer: Transfer, /// The call data of the call. @@ -90,7 +93,7 @@ pub struct CallInputs { #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct CreateInputs { - pub caller: H160, + pub caller: B160, pub scheme: CreateScheme, pub value: U256, #[cfg_attr(feature = "with-serde", serde(with = "serde_hex_bytes"))] @@ -103,7 +106,7 @@ pub struct CreateData {} #[derive(Clone, Debug)] #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub enum TransactTo { - Call(H160), + Call(B160), Create(CreateScheme), } @@ -121,7 +124,7 @@ pub enum TransactOut { Call(Bytes), Create( #[cfg_attr(feature = "with-serde", serde(with = "serde_hex_bytes"))] Bytes, - Option, + Option, ), } @@ -157,11 +160,11 @@ pub enum CallScheme { #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct CallContext { /// Execution address. - pub address: H160, + pub address: B160, /// Caller of the EVM. - pub caller: H160, + pub caller: B160, /// The address the contract code was loaded from, if any. - pub code_address: H160, + pub code_address: B160, /// Apparent value of the EVM. pub apparent_value: U256, /// The scheme used for the call. @@ -171,9 +174,9 @@ pub struct CallContext { impl Default for CallContext { fn default() -> Self { CallContext { - address: H160::default(), - caller: H160::default(), - code_address: H160::default(), + address: B160::default(), + caller: B160::default(), + code_address: B160::default(), apparent_value: U256::default(), scheme: CallScheme::Call, } @@ -193,13 +196,13 @@ pub struct BlockEnv { pub number: U256, /// Coinbase or miner or address that created and signed the block. /// Address where we are going to send gas spend - pub coinbase: H160, + pub coinbase: B160, pub timestamp: U256, /// Difficulty is removed and not used after Paris (aka TheMerge). Value is replaced with prevrandao. pub difficulty: U256, /// Prevrandao is used after Paris (aka TheMerge) instead of the difficulty value. /// NOTE: prevrandao can be found in block in place of mix_hash. - pub prevrandao: Option, + pub prevrandao: Option, /// basefee is added in EIP1559 London upgrade pub basefee: U256, pub gas_limit: U256, @@ -209,7 +212,7 @@ pub struct BlockEnv { #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct TxEnv { /// Caller or Author or tx signer - pub caller: H160, + pub caller: B160, pub gas_limit: u64, pub gas_price: U256, pub gas_priority_fee: Option, @@ -219,7 +222,7 @@ pub struct TxEnv { pub data: Bytes, pub chain_id: Option, pub nonce: Option, - pub access_list: Vec<(H160, Vec)>, + pub access_list: Vec<(B160, Vec)>, } #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] @@ -296,10 +299,10 @@ impl Default for BlockEnv { BlockEnv { gas_limit: U256::MAX, number: U256::ZERO, - coinbase: H160::zero(), + coinbase: B160::zero(), timestamp: U256::from(1), difficulty: U256::ZERO, - prevrandao: Some(H256::zero()), + prevrandao: Some(B256::zero()), basefee: U256::ZERO, } } @@ -308,11 +311,11 @@ impl Default for BlockEnv { impl Default for TxEnv { fn default() -> TxEnv { TxEnv { - caller: H160::zero(), + caller: B160::zero(), gas_limit: u64::MAX, gas_price: U256::ZERO, gas_priority_fee: None, - transact_to: TransactTo::Call(H160::zero()), //will do nothing + transact_to: TransactTo::Call(B160::zero()), //will do nothing value: U256::ZERO, data: Bytes::new(), chain_id: None, @@ -340,9 +343,9 @@ impl Env { #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct Transfer { /// Source address. - pub source: H160, + pub source: B160, /// Target address. - pub target: H160, + pub target: B160, /// Transfer value. pub value: U256, } @@ -350,8 +353,8 @@ pub struct Transfer { #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] pub struct Log { - pub address: H160, - pub topics: Vec, + pub address: B160, + pub topics: Vec, #[cfg_attr(feature = "with-serde", serde(with = "serde_hex_bytes"))] pub data: Bytes, } diff --git a/crates/revm_precompiles/Cargo.toml b/crates/revm_precompiles/Cargo.toml index 0648dd6254..2e2f38efaf 100644 --- a/crates/revm_precompiles/Cargo.toml +++ b/crates/revm_precompiles/Cargo.toml @@ -15,9 +15,8 @@ hashbrown = { version = "0.13" } k256 = { version = "0.11", default-features = false, features = ["ecdsa", "keccak256"], optional = true } num = { version = "0.4.0", default-features = false, features = ["alloc"] } once_cell = "1.14" -primitive-types = { version = "0.12", default-features = false, features = ["rlp"] } ripemd = { version = "0.1", default-features = false } -ruint = "1.4.1" +ruint = { version = "1.7.0", default-features = false} secp256k1 = { version = "0.24.0", default-features = false, features = ["alloc", "recovery"], optional = true } sha2 = { version = "0.10.5", default-features = false } sha3 = { version = "0.10.4", default-features = false } diff --git a/crates/revm_precompiles/src/blake2.rs b/crates/revm_precompiles/src/blake2.rs index 4f43671939..803c644549 100644 --- a/crates/revm_precompiles/src/blake2.rs +++ b/crates/revm_precompiles/src/blake2.rs @@ -1,29 +1,35 @@ -use crate::{gas_query, Return, StandardPrecompileFn}; - -use crate::{Precompile, PrecompileOutput, PrecompileResult}; -use alloc::borrow::Cow; +use crate::{Error, PrecompileAddress, StandardPrecompileFn}; +use crate::{Precompile, PrecompileResult}; use core::convert::TryInto; -use primitive_types::H160 as Address; const F_ROUND: u64 = 1; const INPUT_LENGTH: usize = 213; -pub const FUN: (Address, Precompile) = ( - super::make_address(0, 9), +pub const FUN: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(9), Precompile::Standard(run as StandardPrecompileFn), ); /// reference: https://eips.ethereum.org/EIPS/eip-152 /// input format: /// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f] -fn run(input: &[u8], target_gas: u64) -> PrecompileResult { +fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { if input.len() != INPUT_LENGTH { - return Err(Return::Other(Cow::Borrowed("Invalid last flag for blake2"))); + return Err(Error::Blake2WrongLength); } + let f = match input[212] { + 1 => true, + 0 => false, + _ => return Err(Error::Blake2WrongFinalIndicatorFlag), + }; + // rounds 4 bytes let rounds = u32::from_be_bytes(input[..4].try_into().unwrap()) as usize; - let cost = gas_query(rounds as u64 * F_ROUND, target_gas)?; + let gas_used = rounds as u64 * F_ROUND; + if gas_used > gas_limit { + return Err(Error::OutOfGas); + } let mut h = [0u64; 8]; let mut m = [0u64; 16]; @@ -39,12 +45,6 @@ fn run(input: &[u8], target_gas: u64) -> PrecompileResult { u64::from_le_bytes(input[204..204 + 8].try_into().unwrap()), ]; - let f = match input[212] { - 1 => true, - 0 => false, - _ => return Err(Return::Other(Cow::Borrowed("Invalid last flag for blake2"))), - }; - algo::compress(rounds, &mut h, m, t, f); let mut out = [0u8; 64]; @@ -52,7 +52,7 @@ fn run(input: &[u8], target_gas: u64) -> PrecompileResult { out[i..i + 8].copy_from_slice(&h.to_le_bytes()); } - Ok(PrecompileOutput::without_logs(cost, out.to_vec())) + Ok((gas_used, out.to_vec())) } mod algo { diff --git a/crates/revm_precompiles/src/bn128.rs b/crates/revm_precompiles/src/bn128.rs index 01afb4e016..c2a9d1ef17 100644 --- a/crates/revm_precompiles/src/bn128.rs +++ b/crates/revm_precompiles/src/bn128.rs @@ -1,53 +1,63 @@ -use crate::{gas_query, Precompile, PrecompileOutput, PrecompileResult, Return}; - -use alloc::{borrow::Cow, vec::Vec}; -use primitive_types::H160 as Address; +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, B160}; +use alloc::vec::Vec; use ruint::aliases::U256; pub mod add { use super::*; - const ADDRESS: Address = crate::make_address(0, 6); + const ADDRESS: B160 = crate::u64_to_b160(6); - pub const ISTANBUL: (Address, Precompile) = ( + pub const ISTANBUL: PrecompileAddress = PrecompileAddress( ADDRESS, Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { - super::run_add(input, 150, target_gas) + if 150 > target_gas { + return Err(Error::OutOfGas); + } + Ok((150, super::run_add(input)?)) }), ); - pub const BYZANTIUM: (Address, Precompile) = ( + pub const BYZANTIUM: PrecompileAddress = PrecompileAddress( ADDRESS, Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { - super::run_add(input, 500, target_gas) + if 500 > target_gas { + return Err(Error::OutOfGas); + } + Ok((500, super::run_add(input)?)) }), ); } pub mod mul { use super::*; - const ADDRESS: Address = crate::make_address(0, 7); - pub const ISTANBUL: (Address, Precompile) = ( + const ADDRESS: B160 = crate::u64_to_b160(7); + pub const ISTANBUL: PrecompileAddress = PrecompileAddress( ADDRESS, - Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { - super::run_mul(input, 6_000, target_gas) + Precompile::Standard(|input: &[u8], gas_limit: u64| -> PrecompileResult { + if 6_000 > gas_limit { + return Err(Error::OutOfGas); + } + Ok((6_000, super::run_mul(input)?)) }), ); - pub const BYZANTIUM: (Address, Precompile) = ( + pub const BYZANTIUM: PrecompileAddress = PrecompileAddress( ADDRESS, - Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { - super::run_mul(input, 40_000, target_gas) + Precompile::Standard(|input: &[u8], gas_limit: u64| -> PrecompileResult { + if 40_000 > gas_limit { + return Err(Error::OutOfGas); + } + Ok((40_000, super::run_mul(input)?)) }), ); } pub mod pair { use super::*; - const ADDRESS: Address = crate::make_address(0, 8); + const ADDRESS: B160 = crate::u64_to_b160(8); const ISTANBUL_PAIR_PER_POINT: u64 = 34_000; const ISTANBUL_PAIR_BASE: u64 = 45_000; - pub const ISTANBUL: (Address, Precompile) = ( + pub const ISTANBUL: PrecompileAddress = PrecompileAddress( ADDRESS, Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { super::run_pair( @@ -61,7 +71,7 @@ pub mod pair { const BYZANTIUM_PAIR_PER_POINT: u64 = 80_000; const BYZANTIUM_PAIR_BASE: u64 = 100_000; - pub const BYZANTIUM: (Address, Precompile) = ( + pub const BYZANTIUM: PrecompileAddress = PrecompileAddress( ADDRESS, Precompile::Standard(|input: &[u8], target_gas: u64| -> PrecompileResult { super::run_pair( @@ -84,31 +94,27 @@ const MUL_INPUT_LEN: usize = 128; const PAIR_ELEMENT_LEN: usize = 192; /// Reads the `x` and `y` points from an input at a given position. -fn read_point(input: &[u8], pos: usize) -> Result { +fn read_point(input: &[u8], pos: usize) -> Result { use bn::{AffineG1, Fq, Group, G1}; let mut px_buf = [0u8; 32]; px_buf.copy_from_slice(&input[pos..(pos + 32)]); - let px = Fq::from_slice(&px_buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_X")))?; + let px = Fq::from_slice(&px_buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; let mut py_buf = [0u8; 32]; py_buf.copy_from_slice(&input[(pos + 32)..(pos + 64)]); - let py = Fq::from_slice(&py_buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_Y")))?; + let py = Fq::from_slice(&py_buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; - Ok(if px == Fq::zero() && py == bn::Fq::zero() { - G1::zero() + if px == Fq::zero() && py == bn::Fq::zero() { + Ok(G1::zero()) } else { AffineG1::new(px, py) - .map_err(|_| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_POINT")))? - .into() - }) + .map(Into::into) + .map_err(|_| Error::Bn128AffineGFailedToCreate) + } } -fn run_add(input: &[u8], cost: u64, target_gas: u64) -> PrecompileResult { - let cost = gas_query(cost, target_gas)?; - +fn run_add(input: &[u8]) -> Result, Error> { use bn::AffineG1; let mut input = input.to_vec(); @@ -129,11 +135,10 @@ fn run_add(input: &[u8], cost: u64, target_gas: u64) -> PrecompileResult { .unwrap(); } - Ok(PrecompileOutput::without_logs(cost, output.to_vec())) + Ok(output.into()) } -fn run_mul(input: &[u8], cost: u64, target_gas: u64) -> PrecompileResult { - let cost = gas_query(cost, target_gas)?; +fn run_mul(input: &[u8]) -> Result, Error> { use bn::AffineG1; let mut input = input.to_vec(); @@ -143,8 +148,8 @@ fn run_mul(input: &[u8], cost: u64, target_gas: u64) -> PrecompileResult { let mut fr_buf = [0u8; 32]; fr_buf.copy_from_slice(&input[64..96]); - let fr = bn::Fr::from_slice(&fr_buf[..]) - .map_err(|_| Return::Other(Cow::Borrowed("Invalid field element")))?; + // Fr::from_slice can only fail on incorect length, and this is not a case. + let fr = bn::Fr::from_slice(&fr_buf[..]).unwrap(); let mut out = [0u8; 64]; if let Some(mul) = AffineG1::from_jacobian(p * fr) { @@ -152,22 +157,25 @@ fn run_mul(input: &[u8], cost: u64, target_gas: u64) -> PrecompileResult { mul.y().to_big_endian(&mut out[32..]).unwrap(); } - Ok(PrecompileOutput::without_logs(cost, out.to_vec())) + Ok(out.to_vec()) } fn run_pair( input: &[u8], pair_per_point_cost: u64, pair_base_cost: u64, - target_gas: u64, + gas_limit: u64, ) -> PrecompileResult { - let cost = pair_per_point_cost * input.len() as u64 / PAIR_ELEMENT_LEN as u64 + pair_base_cost; - let cost = gas_query(cost, target_gas)?; + let gas_used = + pair_per_point_cost * input.len() as u64 / PAIR_ELEMENT_LEN as u64 + pair_base_cost; + if gas_used > gas_limit { + return Err(Error::OutOfGas); + } use bn::{AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; if input.len() % PAIR_ELEMENT_LEN != 0 { - return Err(Return::Other(Cow::Borrowed("ERR_BN128_INVALID_LEN"))); + return Err(Error::Bn128PairLength); } let output = if input.is_empty() { @@ -176,46 +184,29 @@ fn run_pair( let elements = input.len() / PAIR_ELEMENT_LEN; let mut vals = Vec::with_capacity(elements); + const PEL: usize = PAIR_ELEMENT_LEN; + for idx in 0..elements { let mut buf = [0u8; 32]; - buf.copy_from_slice(&input[(idx * PAIR_ELEMENT_LEN)..(idx * PAIR_ELEMENT_LEN + 32)]); - let ax = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_AX")))?; - buf.copy_from_slice( - &input[(idx * PAIR_ELEMENT_LEN + 32)..(idx * PAIR_ELEMENT_LEN + 64)], - ); - let ay = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_AY")))?; - buf.copy_from_slice( - &input[(idx * PAIR_ELEMENT_LEN + 64)..(idx * PAIR_ELEMENT_LEN + 96)], - ); - let bay = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_B_AY")))?; - buf.copy_from_slice( - &input[(idx * PAIR_ELEMENT_LEN + 96)..(idx * PAIR_ELEMENT_LEN + 128)], - ); - let bax = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_B_AX")))?; - buf.copy_from_slice( - &input[(idx * PAIR_ELEMENT_LEN + 128)..(idx * PAIR_ELEMENT_LEN + 160)], - ); - let bby = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_B_BY")))?; - buf.copy_from_slice( - &input[(idx * PAIR_ELEMENT_LEN + 160)..(idx * PAIR_ELEMENT_LEN + 192)], - ); - let bbx = Fq::from_slice(&buf) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_B_BX")))?; + buf.copy_from_slice(&input[(idx * PEL)..(idx * PEL + 32)]); + let ax = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; + buf.copy_from_slice(&input[(idx * PEL + 32)..(idx * PEL + 64)]); + let ay = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; + buf.copy_from_slice(&input[(idx * PEL + 64)..(idx * PEL + 96)]); + let bay = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; + buf.copy_from_slice(&input[(idx * PEL + 96)..(idx * PEL + 128)]); + let bax = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; + buf.copy_from_slice(&input[(idx * PEL + 128)..(idx * PEL + 160)]); + let bby = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; + buf.copy_from_slice(&input[(idx * PEL + 160)..(idx * PEL + 192)]); + let bbx = Fq::from_slice(&buf).map_err(|_| Error::Bn128FieldPointNotAMember)?; let a = { if ax.is_zero() && ay.is_zero() { G1::zero() } else { - G1::from( - AffineG1::new(ax, ay) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_A")))?, - ) + G1::from(AffineG1::new(ax, ay).map_err(|_| Error::Bn128AffineGFailedToCreate)?) } }; let b = { @@ -225,10 +216,7 @@ fn run_pair( if ba.is_zero() && bb.is_zero() { G2::zero() } else { - G2::from( - AffineG2::new(ba, bb) - .map_err(|_e| Return::Other(Cow::Borrowed("ERR_BN128_INVALID_B")))?, - ) + G2::from(AffineG2::new(ba, bb).map_err(|_| Error::Bn128AffineGFailedToCreate)?) } }; vals.push((a, b)) @@ -245,10 +233,7 @@ fn run_pair( } }; - Ok(PrecompileOutput::without_logs( - cost, - output.to_be_bytes_vec(), - )) + Ok((gas_used, output.to_be_bytes_vec())) } /* diff --git a/crates/revm_precompiles/src/error.rs b/crates/revm_precompiles/src/error.rs index d9f821f413..1809457de9 100644 --- a/crates/revm_precompiles/src/error.rs +++ b/crates/revm_precompiles/src/error.rs @@ -1,9 +1,16 @@ -use alloc::borrow::Cow; - #[derive(Clone, Debug, Eq, PartialEq)] -pub enum Return { - Exit, +pub enum Error { + /// out of gas is the main error. Other are just here for completness OutOfGas, - /// Other normal errors. - Other(Cow<'static, str>), + // Blake2 erorr + Blake2WrongLength, + Blake2WrongFinalIndicatorFlag, + // Modexp errors + ModexpExpOverflow, + ModexpBaseOverflow, + ModexpModOverflow, + // Bn128 errors + Bn128FieldPointNotAMember, + Bn128AffineGFailedToCreate, + Bn128PairLength, } diff --git a/crates/revm_precompiles/src/hash.rs b/crates/revm_precompiles/src/hash.rs index 0c1985576c..b5b231d660 100644 --- a/crates/revm_precompiles/src/hash.rs +++ b/crates/revm_precompiles/src/hash.rs @@ -1,15 +1,13 @@ -use super::{calc_linear_cost_u32, gas_query}; - -use crate::{Precompile, PrecompileOutput, PrecompileResult, StandardPrecompileFn}; -use primitive_types::H160 as Address; +use super::calc_linear_cost_u32; +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, StandardPrecompileFn}; use sha2::*; -pub const SHA256: (Address, Precompile) = ( - super::make_address(0, 2), +pub const SHA256: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(2), Precompile::Standard(sha256_run as StandardPrecompileFn), ); -pub const RIPEMD160: (Address, Precompile) = ( - super::make_address(0, 3), +pub const RIPEMD160: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(3), Precompile::Standard(ripemd160_run as StandardPrecompileFn), ); @@ -17,17 +15,25 @@ pub const RIPEMD160: (Address, Precompile) = ( /// See: https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions /// See: https://etherscan.io/address/0000000000000000000000000000000000000002 fn sha256_run(input: &[u8], gas_limit: u64) -> PrecompileResult { - let cost = gas_query(calc_linear_cost_u32(input.len(), 60, 12), gas_limit)?; - let output = sha2::Sha256::digest(input).to_vec(); - Ok(PrecompileOutput::without_logs(cost, output)) + let cost = calc_linear_cost_u32(input.len(), 60, 12); + if cost > gas_limit { + Err(Error::OutOfGas) + } else { + let output = sha2::Sha256::digest(input).to_vec(); + Ok((cost, output)) + } } /// See: https://ethereum.github.io/yellowpaper/paper.pdf /// See: https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions /// See: https://etherscan.io/address/0000000000000000000000000000000000000003 fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult { - let gas_used = gas_query(calc_linear_cost_u32(input.len(), 600, 120), gas_limit)?; - let mut ret = [0u8; 32]; - ret[12..32].copy_from_slice(&ripemd::Ripemd160::digest(input)); - Ok(PrecompileOutput::without_logs(gas_used, ret.to_vec())) + let gas_used = calc_linear_cost_u32(input.len(), 600, 120); + if gas_used > gas_limit { + Err(Error::OutOfGas) + } else { + let mut ret = [0u8; 32]; + ret[12..32].copy_from_slice(&ripemd::Ripemd160::digest(input)); + Ok((gas_used, ret.to_vec())) + } } diff --git a/crates/revm_precompiles/src/identity.rs b/crates/revm_precompiles/src/identity.rs index c1c9e9c0d6..9dda458792 100644 --- a/crates/revm_precompiles/src/identity.rs +++ b/crates/revm_precompiles/src/identity.rs @@ -1,10 +1,8 @@ -use crate::{Precompile, PrecompileOutput, PrecompileResult, StandardPrecompileFn}; -use primitive_types::H160 as Address; +use super::calc_linear_cost_u32; +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, StandardPrecompileFn}; -use super::{calc_linear_cost_u32, gas_query}; - -pub const FUN: (Address, Precompile) = ( - super::make_address(0, 4), +pub const FUN: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(4), Precompile::Standard(identity_run as StandardPrecompileFn), ); @@ -18,9 +16,9 @@ const IDENTITY_PER_WORD: u64 = 3; /// See: https://ethereum.github.io/yellowpaper/paper.pdf /// See: https://etherscan.io/address/0000000000000000000000000000000000000004 fn identity_run(input: &[u8], gas_limit: u64) -> PrecompileResult { - let gas_used = gas_query( - calc_linear_cost_u32(input.len(), IDENTITY_BASE, IDENTITY_PER_WORD), - gas_limit, - )?; - Ok(PrecompileOutput::without_logs(gas_used, input.to_vec())) + let gas_used = calc_linear_cost_u32(input.len(), IDENTITY_BASE, IDENTITY_PER_WORD); + if gas_used > gas_limit { + return Err(Error::OutOfGas); + } + Ok((gas_used, input.to_vec())) } diff --git a/crates/revm_precompiles/src/lib.rs b/crates/revm_precompiles/src/lib.rs index c0d1fe2b30..4b1523a2ad 100644 --- a/crates/revm_precompiles/src/lib.rs +++ b/crates/revm_precompiles/src/lib.rs @@ -2,7 +2,9 @@ use bytes::Bytes; use once_cell::sync::OnceCell; -use primitive_types::{H160 as Address, H256}; + +pub type B160 = [u8; 20]; +pub type B256 = [u8; 32]; mod blake2; mod bn128; @@ -12,7 +14,7 @@ mod identity; mod modexp; mod secp256k1; -pub use error::Return; +pub use error::Error; /// libraries for no_std flag #[macro_use] @@ -26,13 +28,6 @@ pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 { (len as u64 + 32 - 1) / 32 * word + base } -pub fn gas_query(gas_used: u64, gas_limit: u64) -> Result { - if gas_used > gas_limit { - return Err(Return::OutOfGas); - } - Ok(gas_used) -} - #[derive(Debug)] pub struct PrecompileOutput { pub cost: u64, @@ -42,8 +37,8 @@ pub struct PrecompileOutput { #[derive(Debug, Default)] pub struct Log { - pub address: Address, - pub topics: Vec, + pub address: B160, + pub topics: Vec, pub data: Bytes, } @@ -58,14 +53,14 @@ impl PrecompileOutput { } /// A precompile operation result. -pub type PrecompileResult = Result; +pub type PrecompileResult = Result<(u64, Vec), Error>; pub type StandardPrecompileFn = fn(&[u8], u64) -> PrecompileResult; pub type CustomPrecompileFn = fn(&[u8], u64) -> PrecompileResult; #[derive(Clone, Debug)] pub struct Precompiles { - fun: HashMap, + fun: HashMap, } impl Default for Precompiles { @@ -89,6 +84,14 @@ impl fmt::Debug for Precompile { } } +pub struct PrecompileAddress(B160, Precompile); + +impl From for (B160, Precompile) { + fn from(value: PrecompileAddress) -> Self { + (value.0, value.1) + } +} + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum SpecId { HOMESTEAD = 0, @@ -115,6 +118,7 @@ impl Precompiles { identity::FUN, ] .into_iter() + .map(From::from) .collect(); Self { fun } }) @@ -134,7 +138,8 @@ impl Precompiles { // EIP-198: Big integer modular exponentiation. modexp::BYZANTIUM, ] - .into_iter(), + .into_iter() + .map(From::from), ); precompiles }) @@ -153,7 +158,8 @@ impl Precompiles { bn128::mul::ISTANBUL, bn128::pair::ISTANBUL, ] - .into_iter(), + .into_iter() + .map(From::from), ); precompiles }) @@ -168,7 +174,8 @@ impl Precompiles { // EIP-2565: ModExp Gas Cost. modexp::BERLIN, ] - .into_iter(), + .into_iter() + .map(From::from), ); precompiles }) @@ -188,15 +195,15 @@ impl Precompiles { } } - pub fn addresses(&self) -> impl IntoIterator { + pub fn addresses(&self) -> impl IntoIterator { self.fun.keys() } - pub fn contains(&self, address: &Address) -> bool { + pub fn contains(&self, address: &B160) -> bool { self.fun.contains_key(address) } - pub fn get(&self, address: &Address) -> Option { + pub fn get(&self, address: &B160) -> Option { //return None; self.fun.get(address).cloned() } @@ -213,29 +220,10 @@ impl Precompiles { /// const fn for making an address by concatenating the bytes from two given numbers, /// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used /// as a convenience for specifying the addresses of the various precompiles. -const fn make_address(x: u32, y: u128) -> Address { +const fn u64_to_b160(x: u64) -> B160 { let x_bytes = x.to_be_bytes(); - let y_bytes = y.to_be_bytes(); - Address([ - x_bytes[0], - x_bytes[1], - x_bytes[2], - x_bytes[3], - y_bytes[0], - y_bytes[1], - y_bytes[2], - y_bytes[3], - y_bytes[4], - y_bytes[5], - y_bytes[6], - y_bytes[7], - y_bytes[8], - y_bytes[9], - y_bytes[10], - y_bytes[11], - y_bytes[12], - y_bytes[13], - y_bytes[14], - y_bytes[15], - ]) + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x_bytes[0], x_bytes[1], x_bytes[2], x_bytes[3], + x_bytes[4], x_bytes[5], x_bytes[6], x_bytes[7], + ] } diff --git a/crates/revm_precompiles/src/modexp.rs b/crates/revm_precompiles/src/modexp.rs index b7c6d6455b..0f68126f83 100644 --- a/crates/revm_precompiles/src/modexp.rs +++ b/crates/revm_precompiles/src/modexp.rs @@ -1,21 +1,19 @@ -use super::gas_query; -use crate::{Precompile, PrecompileOutput, PrecompileResult, StandardPrecompileFn}; +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, StandardPrecompileFn}; use alloc::vec::Vec; use core::{ cmp::{max, min, Ordering}, mem::size_of, }; use num::{BigUint, One, Zero}; -use primitive_types::H160 as Address; use ruint::aliases::U256; -pub const BYZANTIUM: (Address, Precompile) = ( - super::make_address(0, 5), +pub const BYZANTIUM: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(5), Precompile::Standard(byzantium_run as StandardPrecompileFn), ); -pub const BERLIN: (Address, Precompile) = ( - super::make_address(0, 5), +pub const BERLIN: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(5), Precompile::Standard(berlin_run as StandardPrecompileFn), ); @@ -74,7 +72,11 @@ where let (mod_len, mod_overflow) = read_u64_with_overflow!(input, 64, 96, u32::MAX as usize); if base_overflow || mod_overflow { - return Ok(PrecompileOutput::without_logs(u64::MAX, Vec::new())); + return Err(Error::ModexpBaseOverflow); + } + + if mod_overflow { + return Err(Error::ModexpModOverflow); } let (r, gas_cost) = if base_len == 0 && mod_len == 0 { @@ -82,7 +84,7 @@ where } else { // set limit for exp overflow if exp_overflow { - return Ok(PrecompileOutput::without_logs(u64::MAX, Vec::new())); + return Err(Error::ModexpExpOverflow); } let base_start = 96; let base_end = base_start + base_len; @@ -100,10 +102,10 @@ where BigUint::from_bytes_be(&out) }; - let gas_cost = gas_query( - calc_gas(base_len as u64, exp_len as u64, mod_len as u64, &exp_highp), - gas_limit, - )?; + let gas_cost = calc_gas(base_len as u64, exp_len as u64, mod_len as u64, &exp_highp); + if gas_cost > gas_limit { + return Err(Error::OutOfGas); + } let read_big = |from: usize, to: usize| { let mut out = vec![0; to - from]; @@ -129,14 +131,14 @@ where // always true except in the case of zero-length modulus, which leads to // output of length and value 1. match bytes.len().cmp(&mod_len) { - Ordering::Equal => Ok(PrecompileOutput::without_logs(gas_cost, bytes.to_vec())), + Ordering::Equal => Ok((gas_cost, bytes)), Ordering::Less => { let mut ret = Vec::with_capacity(mod_len); ret.extend(core::iter::repeat(0).take(mod_len - bytes.len())); ret.extend_from_slice(&bytes[..]); - Ok(PrecompileOutput::without_logs(gas_cost, ret.to_vec())) + Ok((gas_cost, ret)) } - Ordering::Greater => Ok(PrecompileOutput::without_logs(gas_cost, Vec::new())), + Ordering::Greater => Ok((gas_cost, Vec::new())), } } @@ -378,11 +380,11 @@ mod tests { let res = byzantium_run(&input, 100_000_000).unwrap(); let expected = hex::decode(test.expected).unwrap(); assert_eq!( - res.cost, test_gas, + res.0, test_gas, "used gas not maching for test: {}", test.name ); - assert_eq!(res.output, expected, "test:{}", test.name); + assert_eq!(res.1, expected, "test:{}", test.name); } } @@ -393,11 +395,11 @@ mod tests { let res = berlin_run(&input, 100_000_000).unwrap(); let expected = hex::decode(test.expected).unwrap(); assert_eq!( - res.cost, test_gas, + res.0, test_gas, "used gas not maching for test: {}", test.name ); - assert_eq!(res.output, expected, "test:{}", test.name); + assert_eq!(res.1, expected, "test:{}", test.name); } } @@ -405,6 +407,6 @@ mod tests { fn test_berlin_modexp_empty_input() { let res = berlin_run(&[], 100_000).unwrap(); let expected: Vec = Vec::new(); - assert_eq!(res.output, expected) + assert_eq!(res.1, expected) } } diff --git a/crates/revm_precompiles/src/secp256k1.rs b/crates/revm_precompiles/src/secp256k1.rs index 9e12f9195e..66e2d7ed92 100644 --- a/crates/revm_precompiles/src/secp256k1.rs +++ b/crates/revm_precompiles/src/secp256k1.rs @@ -1,13 +1,11 @@ -use crate::{gas_query, Precompile, PrecompileOutput, PrecompileResult, StandardPrecompileFn}; +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, StandardPrecompileFn}; use alloc::vec::Vec; use core::cmp::min; -use primitive_types::{H160 as Address, H256}; - const ECRECOVER_BASE: u64 = 3_000; -pub const ECRECOVER: (Address, Precompile) = ( - super::make_address(0, 1), +pub const ECRECOVER: PrecompileAddress = PrecompileAddress( + crate::u64_to_b160(1), Precompile::Standard(ec_recover_run as StandardPrecompileFn), ); @@ -20,47 +18,51 @@ mod secp256k1 { elliptic_curve::sec1::ToEncodedPoint, PublicKey as K256PublicKey, }; - use primitive_types::H160 as Address; use sha3::{Digest, Keccak256}; - pub fn ecrecover(sig: &[u8; 65], msg: &[u8; 32]) -> Result { + use crate::B256; + + pub fn ecrecover(sig: &[u8; 65], msg: &B256) -> Result { let sig = recoverable::Signature::try_from(sig.as_ref())?; let verify_key = sig.recover_verifying_key_from_digest_bytes(msg.into())?; let public_key = K256PublicKey::from(&verify_key); let public_key = public_key.to_encoded_point(/* compress = */ false); let public_key = public_key.as_bytes(); let hash = Keccak256::digest(&public_key[1..]); - let mut address = Address::zero(); - address.as_bytes_mut().copy_from_slice(&hash[12..]); - Ok(address) + let mut hash: B256 = hash[..].try_into().unwrap(); + hash.iter_mut().take(12).for_each(|i| *i = 0); + Ok(hash) } } #[cfg(all(not(feature = "k256_ecrecover"), feature = "secp256k1"))] #[allow(clippy::module_inception)] mod secp256k1 { - use primitive_types::H160 as Address; + use crate::B256; use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, Message, Secp256k1, }; use sha3::{Digest, Keccak256}; - pub fn ecrecover(sig: &[u8; 65], msg: &[u8; 32]) -> Result { + pub fn ecrecover(sig: &[u8; 65], msg: &B256) -> Result { let sig = RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?; let secp = Secp256k1::new(); let public = secp.recover_ecdsa(&Message::from_slice(&msg[..32])?, &sig)?; - let mut out = vec![0; 20]; - out.copy_from_slice(&Keccak256::digest(&public.serialize_uncompressed()[1..])[12..]); - Ok(Address::from_slice(&out)) + let hash = Keccak256::digest(&public.serialize_uncompressed()[1..]); + let mut hash: B256 = hash[..].try_into().unwrap(); + hash.iter_mut().take(12).for_each(|i| *i = 0); + Ok(hash) } } fn ec_recover_run(i: &[u8], target_gas: u64) -> PrecompileResult { - let cost = gas_query(ECRECOVER_BASE, target_gas)?; + if ECRECOVER_BASE > target_gas { + return Err(Error::OutOfGas); + } let mut input = [0u8; 128]; input[..min(i.len(), 128)].copy_from_slice(&i[..min(i.len(), 128)]); @@ -72,15 +74,14 @@ fn ec_recover_run(i: &[u8], target_gas: u64) -> PrecompileResult { sig[32..64].copy_from_slice(&input[96..128]); if input[32..63] != [0u8; 31] || !matches!(input[63], 27 | 28) { - return Ok(PrecompileOutput::without_logs(cost, Vec::new())); + return Ok((ECRECOVER_BASE, Vec::new())); } sig[64] = input[63] - 27; - let out = match secp256k1::ecrecover(&sig, &msg) { - Ok(out) => H256::from(out).as_bytes().to_vec(), - Err(_) => Vec::new(), - }; + let out = secp256k1::ecrecover(&sig, &msg) + .map(Vec::from) + .unwrap_or_default(); - Ok(PrecompileOutput::without_logs(cost, out)) + Ok((ECRECOVER_BASE, out)) } diff --git a/crates/revmjs/Cargo.toml b/crates/revmjs/Cargo.toml index e69ab7720f..4fed2156d4 100644 --- a/crates/revmjs/Cargo.toml +++ b/crates/revmjs/Cargo.toml @@ -17,7 +17,7 @@ bytes = "1.2" getrandom = { version = "0.2", features = ["js"] } hex = "0.4" js-sys = "0.3" -primitive-types = { version = "0.12", default-features = false } revm = { path = "../revm", version = "2.0", default-features = false, features = ["k256"] } -ruint = { version = "1.6.0", features = ["primitive-types", "bn-rs"] } +ruint = { version = "1.7.0", features = ["bn-rs"] } wasm-bindgen = "0.2" +primitive-types = "0.12" \ No newline at end of file diff --git a/crates/revmjs/src/lib.rs b/crates/revmjs/src/lib.rs index 63d179a013..74eec5745d 100644 --- a/crates/revmjs/src/lib.rs +++ b/crates/revmjs/src/lib.rs @@ -4,10 +4,9 @@ use bn_rs::BN; use bytes::Bytes; use primitive_types::H160; use revm::{ - AccountInfo, Bytecode, DatabaseCommit, ExecutionResult, InMemoryDB, SpecId, TransactTo, - EVM as rEVM, + AccountInfo, Bytecode, DatabaseCommit, ExecutionResult, InMemoryDB, SpecId, TransactTo, B160, + EVM as rEVM, U256, }; -use ruint::aliases::U256; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -76,7 +75,7 @@ impl EVM { /****** DATABASE RELATED ********/ pub fn insert_account(&mut self, address: BN, nonce: u64, balance: BN, code: &[u8]) { - let address = address.try_into().unwrap(); + let address = B160(>::try_into(address).unwrap().0); let acc_info = AccountInfo::new( balance.try_into().unwrap(), nonce, @@ -107,7 +106,7 @@ impl EVM { self.revm.env.block.number = number.try_into().unwrap(); } pub fn block_coinbase(&mut self, coinbase: BN) { - self.revm.env.block.coinbase = coinbase.try_into().unwrap(); + self.revm.env.block.coinbase = B160(>::try_into(coinbase).unwrap().0); } pub fn block_timestamp(&mut self, timestamp: BN) { self.revm.env.block.timestamp = timestamp.try_into().unwrap(); @@ -122,7 +121,7 @@ impl EVM { /****** ALL TX ENV SETTERS ********/ pub fn tx_caller(&mut self, tx_caller: BN) { - self.revm.env.tx.caller = tx_caller.try_into().unwrap(); + self.revm.env.tx.caller = B160(>::try_into(tx_caller).unwrap().0); } pub fn tx_gas_limit(&mut self, gas_limit: u64) { self.revm.env.tx.gas_limit = gas_limit; @@ -149,7 +148,8 @@ impl EVM { self.revm.env.tx.transact_to = TransactTo::create(); } pub fn tx_transact_to_call(&mut self, to: BN) { - self.revm.env.tx.transact_to = TransactTo::Call(to.try_into().unwrap()); + self.revm.env.tx.transact_to = + TransactTo::Call(B160(>::try_into(to).unwrap().0)); } pub fn tx_accessed_account(&mut self, account: AccessedAccount) { self.revm.env.tx.access_list.push(account.into()) @@ -159,11 +159,11 @@ impl EVM { /// Struct that allows setting AccessList for transaction. #[wasm_bindgen] pub struct AccessedAccount { - account: H160, + account: B160, slots: Vec, } -impl From for (primitive_types::H160, Vec) { +impl From for (B160, Vec) { fn from(from: AccessedAccount) -> Self { (from.account, from.slots) } @@ -173,7 +173,7 @@ impl From for (primitive_types::H160, Vec) { impl AccessedAccount { pub fn new(account: BN) -> Self { Self { - account: H160::try_from(account).unwrap(), + account: B160(>::try_into(account).unwrap().0), slots: Vec::new(), } }