From 85a84c2b3908ef266a90d7a4c69d6a9165860f65 Mon Sep 17 00:00:00 2001 From: mandreyel Date: Mon, 15 May 2023 09:56:04 +0400 Subject: [PATCH 1/2] fix: missing EIP-2718 support checking tx type --- Cargo.lock | 4 +- ethjson/src/test_helpers/state.rs | 11 ++++- evm | 2 +- jsontests/res/ethtests | 2 +- jsontests/src/state.rs | 70 +++++++++++++++++++++++++------ 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86e1b85..685d821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2", diff --git a/ethjson/src/test_helpers/state.rs b/ethjson/src/test_helpers/state.rs index 4da94f7..683f212 100644 --- a/ethjson/src/test_helpers/state.rs +++ b/ethjson/src/test_helpers/state.rs @@ -130,7 +130,7 @@ impl MultiTransaction { r: Default::default(), s: Default::default(), v: Default::default(), - secret: self.secret.clone(), + secret: self.secret, access_list, } } @@ -163,11 +163,16 @@ pub struct PostStateIndexes { /// State test indexed state result deserialization. #[derive(Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct PostStateResult { /// Post state hash pub hash: H256, /// Indexes pub indexes: PostStateIndexes, + /// Expected error if the test is meant to fail + pub expect_exception: Option, + /// Transaction bytes + pub txbytes: Bytes, } #[cfg(test)] @@ -204,20 +209,24 @@ mod tests { "EIP150": [ { "hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f", + "txbytes" : "0xf861800a84042c1d8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b80801ca0f141d67812db948c9a4ea43c27d695248205c121ae8d924d23517ab09e38f369a03fe3cfedb4c9a7e61340b6fec87917690e92082f752ad820ad5006c7d49185ed", "indexes": { "data": 0, "gas": 0, "value": 0 } }, { "hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764", + "txbytes" : "0xf861800a84042c1d8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b80801ca0f141d67812db948c9a4ea43c27d695248205c121ae8d924d23517ab09e38f369a03fe3cfedb4c9a7e61340b6fec87917690e92082f752ad820ad5006c7d49185ed", "indexes": { "data": 0, "gas": 0, "value": 1 } } ], "EIP158": [ { "hash": "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f", + "txbytes" : "0xf861800a84042c1d8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b80801ca0f141d67812db948c9a4ea43c27d695248205c121ae8d924d23517ab09e38f369a03fe3cfedb4c9a7e61340b6fec87917690e92082f752ad820ad5006c7d49185ed", "indexes": { "data": 0, "gas": 0, "value": 0 } }, { "hash": "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764", + "txbytes" : "0xf861800a84042c1d8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b80801ca0f141d67812db948c9a4ea43c27d695248205c121ae8d924d23517ab09e38f369a03fe3cfedb4c9a7e61340b6fec87917690e92082f752ad820ad5006c7d49185ed", "indexes": { "data": 0, "gas": 0, "value": 1 } } ] diff --git a/evm b/evm index 01bcbd2..e7138f7 160000 --- a/evm +++ b/evm @@ -1 +1 @@ -Subproject commit 01bcbd2205a212c34451d3b4fabc962793b057d3 +Subproject commit e7138f7234b117d29d4e653da4967d76e51c5eaf diff --git a/jsontests/res/ethtests b/jsontests/res/ethtests index b25623d..bac70c5 160000 --- a/jsontests/res/ethtests +++ b/jsontests/res/ethtests @@ -1 +1 @@ -Subproject commit b25623d4d7df10e38498cace7adc7eb413c4b20d +Subproject commit bac70c50a579197af68af5fc6d8c7b6163b92c52 diff --git a/jsontests/src/state.rs b/jsontests/src/state.rs index 3d8a3a4..621b93b 100644 --- a/jsontests/src/state.rs +++ b/jsontests/src/state.rs @@ -72,22 +72,21 @@ impl Test { let block_randomness = if spec.is_eth2() { self.0.env.random.map(|r| { - // Convert between U256 and H256. U256 is in little-endian but since H256 is just - // a string-like byte array, it's big endian (MSB is the first element of the array). - // - // Byte order here is important because this opcode has the same value as DIFFICULTY - // (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to - // distinguish between the two: if it's below, the value corresponds to the DIFFICULTY - // opcode, otherwise to the PREVRANDAO opcode. - let mut buf = [0u8; 32]; - r.0.to_big_endian(&mut buf); - H256(buf) - }) + // Convert between U256 and H256. U256 is in little-endian but since H256 is just + // a string-like byte array, it's big endian (MSB is the first element of the array). + // + // Byte order here is important because this opcode has the same value as DIFFICULTY + // (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to + // distinguish between the two: if it's below, the value corresponds to the DIFFICULTY + // opcode, otherwise to the PREVRANDAO opcode. + let mut buf = [0u8; 32]; + r.0.to_big_endian(&mut buf); + H256(buf) + }) } else { None }; - Some(MemoryVicinity { gas_price, origin: self.unwrap_caller(), @@ -261,6 +260,25 @@ fn test_run(name: &str, test: Test) { let transaction = test.0.transaction.select(&state.indexes); let mut backend = MemoryBackend::new(&vicinity, original_state.clone()); + // Test case may be expected to fail with an unsupported tx type if the current fork is + // older than Berlin (see EIP-2718). However, this is not implemented in sputnik itself and rather + // in the code hosting sputnik. https://github.com/rust-blockchain/evm/pull/40 + let tx_type = TxType::from_txbytes(&state.txbytes); + if matches!( + spec, + ForkSpec::EIP150 + | ForkSpec::EIP158 | ForkSpec::Frontier + | ForkSpec::Homestead + | ForkSpec::Byzantium + | ForkSpec::Constantinople + | ForkSpec::ConstantinopleFix + | ForkSpec::Istanbul + ) && tx_type != TxType::Legacy + && state.expect_exception == Some("TR_TypeNotSupported".to_string()) + { + continue; + } + // Only execute valid transactions if let Ok(transaction) = crate::utils::transaction::validate( transaction, @@ -342,3 +360,31 @@ fn test_run(name: &str, test: Test) { } } } + +/// Denotes the type of transaction. +#[derive(Debug, PartialEq)] +enum TxType { + /// All transactions before EIP-2718 are legacy. + Legacy, + /// https://eips.ethereum.org/EIPS/eip-2718 + AccessList, + /// https://eips.ethereum.org/EIPS/eip-1559 + DynamicFee, +} + +impl TxType { + /// Whether this is a legacy, access list, dynamic fee, etc transaction + // Taken from geth's core/types/transaction.go/UnmarshalBinary, but we only detect the transaction + // type rather than unmarshal the entire payload. + fn from_txbytes(txbytes: &[u8]) -> Self { + match txbytes[0] { + b if b > 0x7f => Self::Legacy, + 1 => Self::AccessList, + 2 => Self::DynamicFee, + _ => panic!( + "Unknown tx type. \ +You may need to update the TxType enum if Ethereum introduced new enveloped transaction types." + ), + } + } +} From 4a66053983ff1c5d68252e3c025a352a6d804b75 Mon Sep 17 00:00:00 2001 From: mandreyel Date: Mon, 15 May 2023 09:57:07 +0400 Subject: [PATCH 2/2] fix: missing EIP-2681 for nonce upper bound --- jsontests/src/state.rs | 4 +--- jsontests/src/utils.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/jsontests/src/state.rs b/jsontests/src/state.rs index 621b93b..9c9ed59 100644 --- a/jsontests/src/state.rs +++ b/jsontests/src/state.rs @@ -79,9 +79,7 @@ impl Test { // (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to // distinguish between the two: if it's below, the value corresponds to the DIFFICULTY // opcode, otherwise to the PREVRANDAO opcode. - let mut buf = [0u8; 32]; - r.0.to_big_endian(&mut buf); - H256(buf) + u256_to_h256(r.0) }) } else { None diff --git a/jsontests/src/utils.rs b/jsontests/src/utils.rs index 60bbd39..828eaec 100644 --- a/jsontests/src/utils.rs +++ b/jsontests/src/utils.rs @@ -12,7 +12,7 @@ pub fn u256_to_h256(u: U256) -> H256 { pub fn unwrap_to_account(s: ðjson::spec::Account) -> MemoryAccount { MemoryAccount { balance: s.balance.clone().unwrap().into(), - nonce: s.nonce.clone().unwrap().into(), + nonce: s.nonce.unwrap().0.as_u64(), code: s.code.clone().unwrap().into(), storage: s .storage @@ -48,7 +48,7 @@ pub fn unwrap_to_state(a: ðjson::spec::State) -> BTreeMap