diff --git a/src/bin_evm_proxy/ethereum_types.ml b/src/bin_evm_proxy/ethereum_types.ml index 540a430fbb4a06664356bd0956147142b6cb7c01..148bba44a33babcee4012d7f2748f557d9efb6c4 100644 --- a/src/bin_evm_proxy/ethereum_types.ml +++ b/src/bin_evm_proxy/ethereum_types.ml @@ -337,7 +337,7 @@ type transaction_receipt = { blockHash : block_hash; blockNumber : quantity; from : address; - to_ : address; + to_ : address option; cumulativeGasUsed : quantity; effectiveGasPrice : quantity; gasUsed : quantity; @@ -412,7 +412,7 @@ let transaction_receipt_encoding = (req "blockHash" block_hash_encoding) (req "blockNumber" quantity_encoding) (req "from" address_encoding) - (req "to" address_encoding) + (req "to" (option address_encoding)) (req "cumulativeGasUsed" quantity_encoding) (req "effectiveGasPrice" quantity_encoding) (req "gasUsed" quantity_encoding) diff --git a/src/bin_evm_proxy/mockup.ml b/src/bin_evm_proxy/mockup.ml index 4cef58812c4fead19a36873166408ea219687fb4..3b73b291dc7534c8921405e9c6b0c65fae11ee88 100644 --- a/src/bin_evm_proxy/mockup.ml +++ b/src/bin_evm_proxy/mockup.ml @@ -101,7 +101,7 @@ let transaction_receipt () = blockHash = block_hash; blockNumber = qty_f @@ Z.of_int !block_height_counter; from = address_of_string "0x6F4d14B90C48bEFb49CA3fe6663dEC70731A8bC7"; - to_ = address_of_string "0xA5A5bf58c7Dc91cBE5005A7E5c6314998Eda479E"; + to_ = Some (address_of_string "0xA5A5bf58c7Dc91cBE5005A7E5c6314998Eda479E"); contractAddress = Some (address_of_string "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c"); cumulativeGasUsed = gas_price; diff --git a/src/bin_evm_proxy/rollup_node.ml b/src/bin_evm_proxy/rollup_node.ml index c35c42b0b7a68a69671b969ef2fb5f009b54eec2..e21b0cdd60cf959f6eb29dbcd7791a358f4360ed 100644 --- a/src/bin_evm_proxy/rollup_node.ml +++ b/src/bin_evm_proxy/rollup_node.ml @@ -358,11 +358,15 @@ module RPC = struct let transaction_receipt base (Hash tx_hash) = let open Lwt_result_syntax in - let inspect_durable_and_decode key decode = + let inspect_durable_and_decode_opt key decode = let* bytes = call_service ~base durable_state_value () {key} () in match bytes with - | Some bytes -> return (decode bytes) - | None -> failwith "null" + | Some bytes -> return (Some (decode bytes)) + | None -> return None + in + let inspect_durable_and_decode key decode = + let* opt = inspect_durable_and_decode_opt key decode in + match opt with Some bytes -> return bytes | None -> failwith "null" in let decode_block_hash bytes = Block_hash (Bytes.to_string bytes |> Hex.of_string |> Hex.show) @@ -390,7 +394,7 @@ module RPC = struct in (* This can be none *) let* to_ = - inspect_durable_and_decode + inspect_durable_and_decode_opt (Durable_storage_path.Transaction_receipt.to_ tx_hash) decode_address in diff --git a/src/kernel_evm/ethereum/src/address.rs b/src/kernel_evm/ethereum/src/address.rs deleted file mode 100644 index adeb29a005216bfd535caa5e1c5e984bd3be106d..0000000000000000000000000000000000000000 --- a/src/kernel_evm/ethereum/src/address.rs +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-FileCopyrightText: 2022 TriliTech -// SPDX-FileCopyrightText: 2023 Marigold -// -// SPDX-License-Identifier: MIT - -//! Representation of Ethereum addresses -//! -//! We need to support Ethereum addresses for compatibility, so that -//! we can read Ethereum transactions, etc. -//! -//! Additionally, some addresses have special meaning - for example -//! locations of precompiled contracts or contract creation. -use primitive_types::{H160, H256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp}; - -/// An address of an EVM contract -/// -/// This should be compatible with the Ethereum addresses. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] -pub struct EthereumAddress(H160); - -impl EthereumAddress { - /// Get an address from unsigned 64-bit integer, big endian. - pub fn from_u64_be(v: u64) -> Self { - EthereumAddress(H160::from_low_u64_be(v)) - } - - /// Get an address from a byte array, address if 20 bytes, 0 if no bytes, else error - pub fn from_slice(data: &[u8]) -> Result { - if data.len() == 20 { - Ok(EthereumAddress(H160::from_slice(data))) - } else if data.is_empty() { - Ok(EthereumAddress(H160::zero())) - } else { - Err(DecoderError::Custom("Wrong size for Address")) - } - } -} - -impl From for EthereumAddress { - /// Decode a transaction in hex format. Unsafe, to be used only in tests : panics when fails - fn from(e: String) -> Self { - let data = &hex::decode(e).unwrap(); - EthereumAddress::from_slice(data).unwrap() - } -} - -impl Decodable for EthereumAddress { - fn decode(decoder: &Rlp<'_>) -> Result { - let data = decoder.data()?; - EthereumAddress::from_slice(data) - } -} - -impl Encodable for EthereumAddress { - fn rlp_append(&self, s: &mut rlp::RlpStream) { - if !self.0.is_zero() { - s.append(&self.0); - } else { - // we should make the distinction between 0 and null - // but we don't, null is encoded as 0 - // which is a pb, as the 0x0 address can bu used, to burn stuff - // TODO: https://gitlab.com/tezos/tezos/-/issues/5075 - s.append_empty_data(); - } - } -} - -#[allow(clippy::from_over_into)] -impl Into for EthereumAddress { - fn into(self) -> H160 { - self.0 - } -} - -impl From for String { - fn from(e: EthereumAddress) -> Self { - format!("{:x}", e.0) - } -} - -impl From<[u8; 20]> for EthereumAddress { - fn from(v: [u8; 20]) -> Self { - Self(v.into()) - } -} - -// Use case: coerce a value from the EVM execution stack into an address. This -// is needed for eg contract self destruct (beneficiary address is at top of -// stack and encoded as H256). -impl From for EthereumAddress { - fn from(_v: H256) -> Self { - todo!("See issue: https://gitlab.com/tezos/tezos/-/issues/4902") - } -} - -/// The address for contract used for creating contracts -/// -/// Ethereum has a set of precompiled/special contracts. Creating -/// contracts is implemented as one such contract. -#[allow(dead_code)] -const CREATE_CONTRACT: EthereumAddress = EthereumAddress(H160::zero()); diff --git a/src/kernel_evm/ethereum/src/lib.rs b/src/kernel_evm/ethereum/src/lib.rs index 0299e3eaa5ff61aa4845faf9428c3aae66214fb6..2d3b77de27202d19959c55f837cd088281d876dc 100644 --- a/src/kernel_evm/ethereum/src/lib.rs +++ b/src/kernel_evm/ethereum/src/lib.rs @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -pub mod address; pub mod block; pub mod eth_gen; pub mod signatures; diff --git a/src/kernel_evm/ethereum/src/signatures.rs b/src/kernel_evm/ethereum/src/signatures.rs index fabdea27d503903cd886ad7e37ae22e761a08724..1f675dc316f4a80b5221e7640b33c2cb54864322 100644 --- a/src/kernel_evm/ethereum/src/signatures.rs +++ b/src/kernel_evm/ethereum/src/signatures.rs @@ -11,13 +11,12 @@ use std::array::TryFromSliceError; -use crate::address::EthereumAddress; use hex::FromHexError; use libsecp256k1::{ curve::Scalar, recover, sign, verify, Message, PublicKey, RecoveryId, SecretKey, Signature, }; -use primitive_types::{H256, U256}; +use primitive_types::{H160, H256, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpIterator, RlpStream}; use sha3::{Digest, Keccak256}; use thiserror::Error; @@ -62,7 +61,7 @@ impl From for TransactionError { /// produces address from a secret key pub fn string_to_sk_and_address( s: String, -) -> Result<(SecretKey, EthereumAddress), TransactionError> { +) -> Result<(SecretKey, H160), TransactionError> { let mut data: [u8; 32] = [0u8; 32]; hex::decode_to_slice(s, &mut data)?; let sk = SecretKey::parse(&data)?; @@ -71,7 +70,7 @@ pub fn string_to_sk_and_address( let kec = Keccak256::digest(serialised); let mut value: [u8; 20] = [0u8; 20]; value.copy_from_slice(&kec[12..]); - Ok((sk, EthereumAddress::from(value))) + Ok((sk, value.into())) } /// the type of a transaction @@ -108,7 +107,7 @@ pub struct EthereumTransactionCommon { pub gas_limit: u64, /// The 160-bit address of the message call’s recipient /// or, for a contract creation transaction - pub to: EthereumAddress, + pub to: Option, /// A scalar value equal to the number of Wei to /// be transferred to the message call’s recipient or, /// in the case of contract creation, as an endowment @@ -180,7 +179,7 @@ impl EthereumTransactionCommon { /// for an Ethereum transaction, ie, what address is associated /// with the signature of the message. /// TODO - pub fn caller(&self) -> Result { + pub fn caller(&self) -> Result { let mes = self.message(); let (sig, ri) = self.signature()?; let pk = recover(&mes, &sig, &ri)?; @@ -188,7 +187,7 @@ impl EthereumTransactionCommon { let kec = Keccak256::digest(serialised); let value: [u8; 20] = kec.as_slice()[12..].try_into()?; - Ok(EthereumAddress::from(value)) + Ok(value.into()) } /// compute v from parity and chain_id @@ -317,38 +316,50 @@ fn decode_field_h256( decode_h256(decoder).map_err(custom_err) } +fn decode_field_to(decoder: &Rlp<'_>) -> Result, DecoderError> { + if decoder.is_empty() { + Ok(None) + } else { + let addr: H160 = decode_field(decoder, "to")?; + Ok(Some(addr)) + } +} impl Decodable for EthereumTransactionCommon { fn decode(decoder: &Rlp<'_>) -> Result { - if decoder.is_list() && decoder.item_count() == Ok(9) { - let mut it = decoder.iter(); - let nonce: U256 = decode_field(&next(&mut it)?, "nonce")?; - let gas_price: U256 = decode_field(&next(&mut it)?, "gas_price")?; - let gas_limit: u64 = decode_field(&next(&mut it)?, "gas_limit")?; - let to: EthereumAddress = decode_field(&next(&mut it)?, "to")?; - let value: U256 = decode_field(&next(&mut it)?, "value")?; - let data: Vec = decode_field(&next(&mut it)?, "data")?; - let v: U256 = decode_field(&next(&mut it)?, "v")?; - let r: H256 = decode_field_h256(&next(&mut it)?, "r")?; - let s: H256 = decode_field_h256(&next(&mut it)?, "s")?; - // in a rlp encoded unsigned eip-155 transaction, v is used to store the chainid - // in a rlp encoded signed eip-155 transaction, v is {0,1} + CHAIN_ID * 2 + 35 - let chain_id: U256 = if v > U256::from(35) { - (v - U256::from(35)) / U256::from(2) + if decoder.is_list() { + if Ok(9) == decoder.item_count() { + let mut it = decoder.iter(); + let nonce: U256 = decode_field(&next(&mut it)?, "nonce")?; + let gas_price: U256 = decode_field(&next(&mut it)?, "gas_price")?; + let gas_limit: u64 = decode_field(&next(&mut it)?, "gas_limit")?; + let to: Option = decode_field_to(&next(&mut it)?)?; + let value: U256 = decode_field(&next(&mut it)?, "value")?; + let data: Vec = decode_field(&next(&mut it)?, "data")?; + let v: U256 = decode_field(&next(&mut it)?, "v")?; + let r: H256 = decode_field_h256(&next(&mut it)?, "r")?; + let s: H256 = decode_field_h256(&next(&mut it)?, "s")?; + // in a rlp encoded unsigned eip-155 transaction, v is used to store the chainid + // in a rlp encoded signed eip-155 transaction, v is {0,1} + CHAIN_ID * 2 + 35 + let chain_id: U256 = if v > U256::from(35) { + (v - U256::from(35)) / U256::from(2) + } else { + v + }; + Ok(Self { + chain_id, + nonce, + gas_price, + gas_limit, + to, + value, + data, + v, + r, + s, + }) } else { - v - }; - Ok(Self { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - data, - v, - r, - s, - }) + Err(DecoderError::RlpIncorrectListLen) + } } else { Err(DecoderError::RlpExpectedToBeList) } @@ -361,7 +372,11 @@ impl Encodable for EthereumTransactionCommon { stream.append(&self.nonce); stream.append(&self.gas_price); stream.append(&self.gas_limit); - stream.append_internal(&self.to); + if let Some(addr) = self.to { + stream.append(&addr); + } else { + stream.append_empty_data(); + } stream.append(&self.value); if self.data.is_empty() { // no data == null, not empty vec @@ -389,6 +404,10 @@ mod test { use std::ops::Neg; use super::*; + fn address_from_str(s: &str) -> Option { + let data = &hex::decode(s).unwrap(); + Some(H160::from_slice(data)) + } // utility function to just build a standard correct transaction // extracted from example in EIP 155 standard @@ -403,9 +422,7 @@ mod test { nonce: U256::from(9), gas_price: U256::from(20000000000u64), gas_limit: 21000u64, - to: EthereumAddress::from( - "3535353535353535353535353535353535353535".to_string(), - ), + to: address_from_str("3535353535353535353535353535353535353535"), value: U256::from(1000000000000000000u64), data: vec![], v: U256::from(37), @@ -491,12 +508,8 @@ mod test { let encoded = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83".to_string(); - let expected_address_string: [u8; 20] = - hex::decode("9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F") - .unwrap() - .try_into() - .unwrap(); - let expected_address = EthereumAddress::from(expected_address_string); + let expected_address = + address_from_str("9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F").unwrap(); // act let transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); @@ -557,10 +570,7 @@ mod test { H256::from(v) } - #[test] - fn test_encoding_create() { - // setup - + fn basic_create() -> EthereumTransactionCommon { // transaction "without to field" // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f @@ -568,7 +578,7 @@ mod test { let nonce = U256::from(46); let gas_price = U256::from(29075052730u64); let gas_limit = 274722u64; - let to = EthereumAddress::from("".to_string()); + let to = None; let value = U256::from(1000000000u64); let data: Vec = hex::decode("ffff").unwrap(); let chain_id = U256::one(); @@ -579,7 +589,7 @@ mod test { let s = string_to_h256_unsafe( "57854e7044a8fee7bccb6a2c32c4229dd9cbacad74350789e0ce75bf40b6f713", ); - let expected_transaction = EthereumTransactionCommon { + EthereumTransactionCommon { chain_id, nonce, gas_price, @@ -590,15 +600,36 @@ mod test { v, r, s, - }; + } + } + + #[test] + fn test_encoding_create() { + // setup + let transaction = basic_create(); + let expected_encoded = "f8572e8506c50218ba8304312280843b9aca0082ffff26a0e9637495be4c216a833ef390b1f6798917c8a102ab165c5085cced7ca1f2eb3aa057854e7044a8fee7bccb6a2c32c4229dd9cbacad74350789e0ce75bf40b6f713"; + // act + let encoded = transaction.rlp_bytes(); + + // assert + assert_eq!(expected_encoded, hex::encode(&encoded)); + } + + #[test] + fn test_decoding_create() { + // setup + let expected_transaction = basic_create(); let signed_tx = "f8572e8506c50218ba8304312280843b9aca0082ffff26a0e9637495be4c216a833ef390b1f6798917c8a102ab165c5085cced7ca1f2eb3aa057854e7044a8fee7bccb6a2c32c4229dd9cbacad74350789e0ce75bf40b6f713"; // act - let encoded = expected_transaction.rlp_bytes(); + let tx = hex::decode(signed_tx).unwrap(); + let decoder = Rlp::new(&tx); + let decoded = EthereumTransactionCommon::decode(&decoder); // assert - assert_eq!(signed_tx, hex::encode(&encoded)); + assert!(decoded.is_ok()); + assert_eq!(expected_transaction, decoded.unwrap()); } #[test] @@ -621,8 +652,7 @@ mod test { let nonce = U256::from(0); let gas_price = U256::from(40000000000u64); let gas_limit = 21000u64; - let to = - EthereumAddress::from("423163e58aabec5daa3dd1130b759d24bef0f6ea".to_string()); + let to = address_from_str("423163e58aabec5daa3dd1130b759d24bef0f6ea"); let value = U256::from(5000000000000000u64); let data: Vec = hex::decode("deace8f5000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000041bca408a6b4029b42883aeb2c25087cab76cb58000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000002357a49c7d75f600000000000000000000000000000000000000000000000000000000640b5549000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d5640000000000000000000000000000000000000000000000000000000000000000").unwrap(); let v = U256::from(37); @@ -685,8 +715,7 @@ mod test { let nonce = U256::from(46); let gas_price = U256::from(29075052730u64); let gas_limit = 274722u64; - let to = - EthereumAddress::from("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b".to_string()); + let to = address_from_str("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"); let value = U256::from(760460536160301065u64); // /!\ > 2^53 -1 let data: Vec = hex::decode("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000").unwrap(); let v = U256::from(37); @@ -732,8 +761,7 @@ mod test { let nonce = U256::from(46); let gas_price = U256::from(29075052730u64); let gas_limit = 274722u64; - let to = - EthereumAddress::from("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b".to_string()); + let to = address_from_str("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"); let value = U256::from(760460536160301065u64); // /!\ > 2^53 -1 let data: Vec = hex::decode("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000").unwrap(); let v = U256::from(37); @@ -785,9 +813,7 @@ mod test { nonce: U256::from(1), gas_price: U256::from(30000000000u64), gas_limit: 1048576u64, - to: EthereumAddress::from( - "4e1b2c985d729ae6e05ef7974013eeb48f394449".to_string(), - ), + to: address_from_str("4e1b2c985d729ae6e05ef7974013eeb48f394449"), value: U256::from(1000000000u64), data: vec![], v: U256::from(38), @@ -829,9 +855,7 @@ mod test { nonce: U256::from(1), gas_price: U256::from(30000000000u64), gas_limit: 1048576u64, - to: EthereumAddress::from( - "4e1b2c985d729ae6e05ef7974013eeb48f394449".to_string(), - ), + to: address_from_str("4e1b2c985d729ae6e05ef7974013eeb48f394449"), value: U256::from(1000000000u64), data: vec![], v: U256::from(38), @@ -845,9 +869,7 @@ mod test { // assert assert_eq!( - Ok(EthereumAddress::from( - "d9e5c94a12f78a96640757ac97ba0c257e8aa262".to_string() - )), + Ok(address_from_str("d9e5c94a12f78a96640757ac97ba0c257e8aa262").unwrap()), transaction.caller(), "test field from" ) @@ -874,9 +896,7 @@ mod test { nonce: U256::from(1), gas_price: U256::from(30000000000u64), gas_limit: 1048576u64, - to: EthereumAddress::from( - "4e1b2c985d729ae6e05ef7974013eeb48f394449".to_string(), - ), + to: address_from_str("4e1b2c985d729ae6e05ef7974013eeb48f394449"), value: U256::from(1000000000u64), data: vec![], v: U256::one(), @@ -912,12 +932,8 @@ mod test { .to_string(); let (_sk, address) = string_to_sk_and_address(sk.clone()).unwrap(); // Check that the derived address is the expected one. - let expected_address_string: [u8; 20] = - hex::decode(b"6471A723296395CF1Dcc568941AFFd7A390f94CE") - .unwrap() - .try_into() - .unwrap(); - let expected_address = EthereumAddress::from(expected_address_string); + let expected_address = + address_from_str("6471A723296395CF1Dcc568941AFFd7A390f94CE").unwrap(); assert_eq!(expected_address, address); // Check that the derived sender address is the expected one. @@ -935,7 +951,7 @@ mod test { fn test_caller_eip155_example() { let transaction = basic_eip155_transaction(); assert_eq!( - EthereumAddress::from("9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f".to_string()), + address_from_str("9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f").unwrap(), transaction.caller().unwrap() ) } @@ -993,9 +1009,7 @@ mod test { nonce: U256::from(46), gas_price: U256::from(29075052730u64), gas_limit: 274722u64, - to: EthereumAddress::from( - "ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b".to_string(), - ), + to: address_from_str("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"), value: U256::from(760460536160301065u64), data, v: U256::from(37), @@ -1009,9 +1023,7 @@ mod test { // check assert_eq!( - Ok(EthereumAddress::from( - "af1276cbb260bb13deddb4209ae99ae6e497f446".to_string() - )), + Ok(address_from_str("af1276cbb260bb13deddb4209ae99ae6e497f446").unwrap()), transaction.caller(), "checking caller" ) @@ -1029,9 +1041,7 @@ mod test { nonce: U256::from(46), gas_price: U256::from(29075052730u64), gas_limit: 274722u64, - to: EthereumAddress::from( - "ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b".to_string(), - ), + to: address_from_str("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"), value: U256::from(760460536160301065u64), data, v: U256::one(), @@ -1064,9 +1074,7 @@ mod test { nonce: U256::from(46), gas_price: U256::from(29075052730u64), gas_limit: 274722u64, - to: EthereumAddress::from( - "ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b".to_string(), - ), + to: address_from_str("ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"), value: U256::from(760460536160301065u64), data, v: U256::zero(), diff --git a/src/kernel_evm/ethereum/src/transaction.rs b/src/kernel_evm/ethereum/src/transaction.rs index 3a73f1d581897a9751eda621ddece2650e2f1ba3..b9a30dc7057524cb0fb57b2a0db42d5d1f29d662 100644 --- a/src/kernel_evm/ethereum/src/transaction.rs +++ b/src/kernel_evm/ethereum/src/transaction.rs @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -use crate::address::EthereumAddress; use primitive_types::{H160, H256, U256}; pub const TRANSACTION_HASH_SIZE: usize = 32; @@ -62,9 +61,9 @@ pub struct TransactionReceipt { /// Block number where this transaction was in. pub block_number: U256, /// Address of the sender. - pub from: EthereumAddress, + pub from: H160, /// Address of the receiver. null when its a contract creation transaction. - pub to: Option, + pub to: Option, /// The total amount of gas used when this transaction was executed in the block pub cumulative_gas_used: U256, /// The sum of the base fee and tip paid per unit of gas. diff --git a/src/kernel_evm/evm_execution/src/lib.rs b/src/kernel_evm/evm_execution/src/lib.rs index dbf049e483526113e8affcf24df46d263f049b3b..ecb560d4334e151b32205d5b91e10f7df68a52e8 100644 --- a/src/kernel_evm/evm_execution/src/lib.rs +++ b/src/kernel_evm/evm_execution/src/lib.rs @@ -91,7 +91,7 @@ pub fn run_transaction<'a, Host>( block: &'a BlockConstants, evm_account_storage: &'a mut EthereumAccountStorage, precompiles: &'a precompiles::PrecompileBTreeMap, - address: H160, + address: Option, caller: H160, call_data: Vec, gas_limit: Option, @@ -102,7 +102,7 @@ where { debug_msg!(host, "Going to run an Ethereum transaction"); debug_msg!(host, " - from address: {}", caller); - debug_msg!(host, " - to address: {}", address); + debug_msg!(host, " - to address: {:?}", address); let config = Config::london(); let mut handler = handler::EvmHandler::<'_, Host>::new( @@ -118,15 +118,17 @@ where // TODO: check gas_limit vs caller balance. Make sure caller has // enough funds to pay for gas. - if call_data.is_empty() { - // This is a transfer transaction - handler.transfer(caller, address, value.unwrap_or(U256::zero()), gas_limit) - } else if address.is_zero() { + if let Some(address) = address { + if call_data.is_empty() { + // This is a transfer transaction + handler.transfer(caller, address, value.unwrap_or(U256::zero()), gas_limit) + } else { + // This must be a contract-call transaction + handler.call_contract(caller, address, value, call_data, gas_limit, false) + } + } else { // This is a create-contract transaction handler.create_contract(caller, value, call_data, gas_limit) - } else { - // This must be a contract-call transaction - handler.call_contract(caller, address, value, call_data, gas_limit, false) } } @@ -142,7 +144,6 @@ mod test { use host::runtime::Runtime; use primitive_types::H160; use std::str::FromStr; - use tezos_ethereum::address::EthereumAddress; use tezos_ethereum::signatures::EthereumTransactionCommon; use tezos_smart_rollup_mock::MockHost; @@ -229,7 +230,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - callee, + Some(callee), caller, call_data, Some(22000), @@ -285,7 +286,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - callee, + Some(callee), caller, call_data, Some(21000), @@ -318,7 +319,7 @@ mod test { let precompiles = precompiles::precompile_set::(); let mut evm_account_storage = init_evm_account_storage().unwrap(); - let callee = H160::zero(); + let callee = None; let caller = H160::from_low_u64_be(328794); let transaction_value = U256::from(100_u32); let call_data: Vec = hex::decode(STORAGE_CONTRACT_INITIALIZATION).unwrap(); @@ -363,7 +364,7 @@ mod test { let precompiles = precompiles::precompile_set::(); let mut evm_account_storage = init_evm_account_storage().unwrap(); - let callee = H160::zero(); + let callee = None; let caller = H160::from_low_u64_be(117); let transaction_value = U256::from(0); let call_data: Vec = hex::decode(STORAGE_CONTRACT_INITIALIZATION).unwrap(); @@ -406,7 +407,7 @@ mod test { let precompiles = precompiles::precompile_set::(); let mut evm_account_storage = init_evm_account_storage().unwrap(); - let callee = H160::zero(); + let callee = None; let caller = H160::from_low_u64_be(117); let transaction_value = U256::from(0); let call_data: Vec = hex::decode(ERC20_CONTRACT_INITIALISATION).unwrap(); @@ -447,7 +448,7 @@ mod test { let precompiles = precompiles::precompile_set::(); let mut evm_account_storage = init_evm_account_storage().unwrap(); - let callee = H160::zero(); + let callee = None; let caller = H160::from_low_u64_be(2893); let transaction_value = U256::from(100_u32); // Some EVM instructions. They are all valid, but the last one is opcode @@ -505,7 +506,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), None, @@ -571,7 +572,7 @@ mod test { tezos_ethereum::signatures::string_to_sk_and_address(s.to_string()) .unwrap(); let value: [u8; 20] = hex::decode(ea).unwrap().try_into().unwrap(); - let ea = EthereumAddress::from(value); + let ea = value.into(); assert_eq!(a, ea); }) } @@ -593,7 +594,7 @@ mod test { .unwrap() .try_into() .unwrap(); - let expected_address = EthereumAddress::from(expected_address_string); + let expected_address: H160 = expected_address_string.into(); assert_eq!(expected_address, address); assert_eq!(expected_address, address_from_sk) } @@ -637,7 +638,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(6), @@ -681,7 +682,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(6), @@ -726,7 +727,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), None, @@ -775,7 +776,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - address, + Some(address), caller, input, None, @@ -817,7 +818,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(1), @@ -918,7 +919,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), None, diff --git a/src/kernel_evm/kernel/src/block.rs b/src/kernel_evm/kernel/src/block.rs index aedd57fa542e20e8a7b6ded3a42313193c9eacf4..6d461c120daff93f182215b3c93f99b7b29b1487 100644 --- a/src/kernel_evm/kernel/src/block.rs +++ b/src/kernel_evm/kernel/src/block.rs @@ -15,11 +15,10 @@ use evm_execution::account_storage::EthereumAccountStorage; use evm_execution::handler::ExecutionOutcome; use evm_execution::{precompiles, run_transaction}; -use tezos_ethereum::address::EthereumAddress; use tezos_ethereum::transaction::TransactionHash; use tezos_smart_rollup_host::runtime::Runtime; -use primitive_types::U256; +use primitive_types::{H160, U256}; use tezos_ethereum::block::L2Block; use tezos_ethereum::transaction::{ TransactionReceipt, TransactionStatus, TransactionType, @@ -29,16 +28,16 @@ struct TransactionReceiptInfo { tx_hash: TransactionHash, index: u32, execution_outcome: Option, - caller: EthereumAddress, - to: EthereumAddress, + caller: H160, + to: Option, } fn make_receipt_info( tx_hash: TransactionHash, index: u32, execution_outcome: Option, - caller: EthereumAddress, - to: EthereumAddress, + caller: H160, + to: Option, ) -> TransactionReceiptInfo { TransactionReceiptInfo { tx_hash, @@ -59,7 +58,7 @@ fn make_receipt( let block_hash = block.hash; let block_number = block.number; let from = receipt_info.caller; - let to = Some(receipt_info.to); + let to = receipt_info.to; let effective_gas_price = block.constants().gas_price; let tx_receipt = match receipt_info.execution_outcome { @@ -116,12 +115,11 @@ fn make_receipts( fn check_nonce( host: &mut Host, tx_nonce: U256, - caller: EthereumAddress, + caller: H160, evm_account_storage: &mut EthereumAccountStorage, ) -> Result<(), Error> { - let caller_account_path = - evm_execution::account_storage::account_path(&caller.into()) - .map_err(|_| Error::Storage(AccountInitialisation))?; + let caller_account_path = evm_execution::account_storage::account_path(&caller) + .map_err(|_| Error::Storage(AccountInitialisation))?; let caller_account = evm_account_storage .get(host, &caller_account_path) .map_err(|_| Error::Storage(AccountInitialisation))?; @@ -163,8 +161,8 @@ pub fn produce(host: &mut Host, queue: Queue) -> Result<(), Error ¤t_block.constants(), &mut evm_account_storage, &precompiles, - transaction.tx.to.into(), - caller.into(), + transaction.tx.to, + caller, transaction.tx.data, Some(transaction.tx.gas_limit), Some(transaction.tx.value), @@ -213,11 +211,14 @@ mod tests { use evm_execution::account_storage::{account_path, EthereumAccountStorage}; use primitive_types::{H160, H256}; use std::str::FromStr; - use tezos_ethereum::address::EthereumAddress; use tezos_ethereum::signatures::EthereumTransactionCommon; use tezos_ethereum::transaction::{TransactionStatus, TRANSACTION_HASH_SIZE}; use tezos_smart_rollup_mock::MockHost; + fn address_from_str(s: &str) -> Option { + let data = &hex::decode(s).unwrap(); + Some(H160::from_slice(data)) + } fn string_to_h256_unsafe(s: &str) -> H256 { let mut v: [u8; 32] = [0; 32]; hex::decode_to_slice(s, &mut v).expect("Could not parse to 256 hex value."); @@ -265,8 +266,7 @@ mod tests { let chain_id = U256::one(); let gas_price = U256::from(40000000u64); let gas_limit = 21000u64; - let to = - EthereumAddress::from("423163e58aabec5daa3dd1130b759d24bef0f6ea".to_string()); + let to = address_from_str("423163e58aabec5daa3dd1130b759d24bef0f6ea"); let value = U256::from(500000000u64); let data: Vec = vec![]; EthereumTransactionCommon { diff --git a/src/kernel_evm/kernel/src/genesis.rs b/src/kernel_evm/kernel/src/genesis.rs index c7738120daec6a1a951a2d45480b683ee2380a3e..115d427fdac5c013f74f44d8b7607659d290871e 100644 --- a/src/kernel_evm/kernel/src/genesis.rs +++ b/src/kernel_evm/kernel/src/genesis.rs @@ -15,7 +15,6 @@ use evm_execution::account_storage::init_account_storage; use evm_execution::account_storage::AccountStorageError; use evm_execution::account_storage::EthereumAccountStorage; use primitive_types::{H160, U256}; -use tezos_ethereum::address::EthereumAddress; use tezos_ethereum::transaction::TransactionHash; use tezos_ethereum::transaction::TransactionReceipt; use tezos_ethereum::transaction::TransactionStatus; @@ -107,7 +106,7 @@ fn bootstrap_genesis_accounts( collect_mint_transactions(transactions_hashes) } -fn craft_mint_address(genesis_mint_address: &str) -> Option { +fn craft_mint_address(genesis_mint_address: &str) -> Option { let encoded_genesis_mint_address: Vec = hex::decode(genesis_mint_address).ok()?; let encoded_genesis_mint_address: [u8; 20] = encoded_genesis_mint_address.try_into().ok()?; @@ -118,7 +117,7 @@ fn store_genesis_receipts( host: &mut Host, genesis_block: L2Block, ) -> Result<(), Error> { - let genesis_address: EthereumAddress = GENESIS_ADDRESSS.into(); + let genesis_address: H160 = GENESIS_ADDRESSS.into(); for (hash, index) in genesis_block.transactions.iter().zip(0u32..) { let mint_account = &MINT_ACCOUNTS[index as usize]; diff --git a/src/kernel_evm/kernel/src/storage.rs b/src/kernel_evm/kernel/src/storage.rs index 8e8cd6c4f2b61a9d4e68d4f8a77d5621ca98795e..4b0e10611da6d4df0e7d1004049f621d0c89c3f0 100644 --- a/src/kernel_evm/kernel/src/storage.rs +++ b/src/kernel_evm/kernel/src/storage.rs @@ -290,7 +290,7 @@ pub fn store_transaction_receipt( host.store_write(&block_number_path, &le_receipt_block_number, 0)?; // From let from_path = concat(receipt_path, &TRANSACTION_RECEIPT_FROM)?; - let from: H160 = receipt.from.into(); + let from: H160 = receipt.from; host.store_write(&from_path, from.as_bytes(), 0)?; // Type let type_path = concat(receipt_path, &TRANSACTION_RECEIPT_TYPE)?; @@ -300,7 +300,6 @@ pub fn store_transaction_receipt( host.store_write(&status_path, (&receipt.status).into(), 0)?; // To if let Some(to) = receipt.to { - let to: H160 = to.into(); let to_path = concat(receipt_path, &TRANSACTION_RECEIPT_TO)?; host.store_write(&to_path, to.as_bytes(), 0)?; }; diff --git a/src/kernel_evm/kernel_benchmark/src/inbox.rs b/src/kernel_evm/kernel_benchmark/src/inbox.rs index 72b7521f5b4558f1d7465b517a744a083ada0214..5d9d87f98fc82357c28c8218ff7d98b3f2c95699 100644 --- a/src/kernel_evm/kernel_benchmark/src/inbox.rs +++ b/src/kernel_evm/kernel_benchmark/src/inbox.rs @@ -106,8 +106,8 @@ where block, evm_account_storage, precompiles, - e.to.into(), - e.caller()?.into(), + e.to, + e.caller()?, e.data, Some(e.gas_limit), Some(e.value),