From dc75269a096ea7906257c09f305853b0b557fdfb Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Fri, 12 May 2023 19:53:20 +0200 Subject: [PATCH 1/2] SORU: EVM: make field 'to' truly optionnal --- src/bin_evm_proxy/ethereum_types.ml | 4 +- src/bin_evm_proxy/mockup.ml | 2 +- src/bin_evm_proxy/rollup_node.ml | 12 +- src/kernel_evm/ethereum/src/address.rs | 5 + src/kernel_evm/ethereum/src/signatures.rs | 154 +++++++++++-------- src/kernel_evm/evm_execution/src/lib.rs | 46 +++--- src/kernel_evm/kernel/src/block.rs | 14 +- src/kernel_evm/kernel_benchmark/src/inbox.rs | 2 +- 8 files changed, 136 insertions(+), 103 deletions(-) diff --git a/src/bin_evm_proxy/ethereum_types.ml b/src/bin_evm_proxy/ethereum_types.ml index 540a430fbb4a..148bba44a33b 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 4cef58812c4f..3b73b291dc75 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 c35c42b0b7a6..e21b0cdd60cf 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 index adeb29a00521..2345769119e9 100644 --- a/src/kernel_evm/ethereum/src/address.rs +++ b/src/kernel_evm/ethereum/src/address.rs @@ -73,6 +73,11 @@ impl Into for EthereumAddress { } } +impl From for EthereumAddress { + fn from(addr: H160) -> Self { + Self(addr) + } +} impl From for String { fn from(e: EthereumAddress) -> Self { format!("{:x}", e.0) diff --git a/src/kernel_evm/ethereum/src/signatures.rs b/src/kernel_evm/ethereum/src/signatures.rs index fabdea27d503..d8766d1a7ebd 100644 --- a/src/kernel_evm/ethereum/src/signatures.rs +++ b/src/kernel_evm/ethereum/src/signatures.rs @@ -108,7 +108,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 @@ -317,38 +317,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: EthereumAddress = 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 +373,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_internal(&addr); + } else { + stream.append_empty_data(); + } stream.append(&self.value); if self.data.is_empty() { // no data == null, not empty vec @@ -389,6 +405,9 @@ mod test { use std::ops::Neg; use super::*; + fn address_from_str(s: &str) -> Option { + Some(EthereumAddress::from(s.to_string())) + } // 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), @@ -557,10 +574,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 +582,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 +593,7 @@ mod test { let s = string_to_h256_unsafe( "57854e7044a8fee7bccb6a2c32c4229dd9cbacad74350789e0ce75bf40b6f713", ); - let expected_transaction = EthereumTransactionCommon { + EthereumTransactionCommon { chain_id, nonce, gas_price, @@ -590,15 +604,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 +656,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 +719,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 +765,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 +817,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 +859,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), @@ -874,9 +902,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(), @@ -993,9 +1019,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), @@ -1029,9 +1053,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 +1086,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/evm_execution/src/lib.rs b/src/kernel_evm/evm_execution/src/lib.rs index dbf049e48352..17b5d7d94f8c 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) } } @@ -229,7 +231,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - callee, + Some(callee), caller, call_data, Some(22000), @@ -285,7 +287,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - callee, + Some(callee), caller, call_data, Some(21000), @@ -318,7 +320,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 +365,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 +408,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 +449,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 +507,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), None, @@ -637,7 +639,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(6), @@ -681,7 +683,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(6), @@ -726,7 +728,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), None, @@ -775,7 +777,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - address, + Some(address), caller, input, None, @@ -817,7 +819,7 @@ mod test { &block, &mut evm_account_storage, &precompiles, - target, + Some(target), caller, data.to_vec(), Some(1), @@ -918,7 +920,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 aedd57fa542e..1cbd2b28d955 100644 --- a/src/kernel_evm/kernel/src/block.rs +++ b/src/kernel_evm/kernel/src/block.rs @@ -30,7 +30,7 @@ struct TransactionReceiptInfo { index: u32, execution_outcome: Option, caller: EthereumAddress, - to: EthereumAddress, + to: Option, } fn make_receipt_info( @@ -38,7 +38,7 @@ fn make_receipt_info( index: u32, execution_outcome: Option, caller: EthereumAddress, - to: EthereumAddress, + to: Option, ) -> TransactionReceiptInfo { TransactionReceiptInfo { tx_hash, @@ -59,7 +59,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 { @@ -163,7 +163,7 @@ pub fn produce(host: &mut Host, queue: Queue) -> Result<(), Error ¤t_block.constants(), &mut evm_account_storage, &precompiles, - transaction.tx.to.into(), + transaction.tx.to.map(|a| a.into()), caller.into(), transaction.tx.data, Some(transaction.tx.gas_limit), @@ -218,6 +218,9 @@ mod tests { use tezos_ethereum::transaction::{TransactionStatus, TRANSACTION_HASH_SIZE}; use tezos_smart_rollup_mock::MockHost; + fn address_from_str(s: &str) -> Option { + Some(EthereumAddress::from(s.to_string())) + } 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 +268,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_benchmark/src/inbox.rs b/src/kernel_evm/kernel_benchmark/src/inbox.rs index 72b7521f5b45..e550e593faeb 100644 --- a/src/kernel_evm/kernel_benchmark/src/inbox.rs +++ b/src/kernel_evm/kernel_benchmark/src/inbox.rs @@ -106,7 +106,7 @@ where block, evm_account_storage, precompiles, - e.to.into(), + e.to.map(|addr| addr.into()), e.caller()?.into(), e.data, Some(e.gas_limit), -- GitLab From 40e168411847e5b6602232dfffcfb1315e2bee83 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Tue, 16 May 2023 16:26:48 +0200 Subject: [PATCH 2/2] SORU: EVM: remove EthereumAddress --- src/kernel_evm/ethereum/src/address.rs | 107 ------------------- src/kernel_evm/ethereum/src/lib.rs | 1 - src/kernel_evm/ethereum/src/signatures.rs | 52 ++++----- src/kernel_evm/ethereum/src/transaction.rs | 5 +- src/kernel_evm/evm_execution/src/lib.rs | 5 +- src/kernel_evm/kernel/src/block.rs | 28 +++-- src/kernel_evm/kernel/src/genesis.rs | 5 +- src/kernel_evm/kernel/src/storage.rs | 3 +- src/kernel_evm/kernel_benchmark/src/inbox.rs | 4 +- 9 files changed, 42 insertions(+), 168 deletions(-) delete mode 100644 src/kernel_evm/ethereum/src/address.rs diff --git a/src/kernel_evm/ethereum/src/address.rs b/src/kernel_evm/ethereum/src/address.rs deleted file mode 100644 index 2345769119e9..000000000000 --- a/src/kernel_evm/ethereum/src/address.rs +++ /dev/null @@ -1,107 +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 EthereumAddress { - fn from(addr: H160) -> Self { - Self(addr) - } -} -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 0299e3eaa5ff..2d3b77de2720 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 d8766d1a7ebd..1f675dc316f4 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: Option, + 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,11 +316,11 @@ fn decode_field_h256( decode_h256(decoder).map_err(custom_err) } -fn decode_field_to(decoder: &Rlp<'_>) -> Result, DecoderError> { +fn decode_field_to(decoder: &Rlp<'_>) -> Result, DecoderError> { if decoder.is_empty() { Ok(None) } else { - let addr: EthereumAddress = decode_field(decoder, "to")?; + let addr: H160 = decode_field(decoder, "to")?; Ok(Some(addr)) } } @@ -333,7 +332,7 @@ impl Decodable for EthereumTransactionCommon { 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 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")?; @@ -374,7 +373,7 @@ impl Encodable for EthereumTransactionCommon { stream.append(&self.gas_price); stream.append(&self.gas_limit); if let Some(addr) = self.to { - stream.append_internal(&addr); + stream.append(&addr); } else { stream.append_empty_data(); } @@ -405,8 +404,9 @@ mod test { use std::ops::Neg; use super::*; - fn address_from_str(s: &str) -> Option { - Some(EthereumAddress::from(s.to_string())) + 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 @@ -508,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(); @@ -873,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" ) @@ -938,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. @@ -961,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() ) } @@ -1033,9 +1023,7 @@ mod test { // check assert_eq!( - Ok(EthereumAddress::from( - "af1276cbb260bb13deddb4209ae99ae6e497f446".to_string() - )), + Ok(address_from_str("af1276cbb260bb13deddb4209ae99ae6e497f446").unwrap()), transaction.caller(), "checking caller" ) diff --git a/src/kernel_evm/ethereum/src/transaction.rs b/src/kernel_evm/ethereum/src/transaction.rs index 3a73f1d58189..b9a30dc70575 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 17b5d7d94f8c..ecb560d4334e 100644 --- a/src/kernel_evm/evm_execution/src/lib.rs +++ b/src/kernel_evm/evm_execution/src/lib.rs @@ -144,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; @@ -573,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); }) } @@ -595,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) } diff --git a/src/kernel_evm/kernel/src/block.rs b/src/kernel_evm/kernel/src/block.rs index 1cbd2b28d955..6d461c120daf 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: Option, + caller: H160, + to: Option, } fn make_receipt_info( tx_hash: TransactionHash, index: u32, execution_outcome: Option, - caller: EthereumAddress, - to: Option, + caller: H160, + to: Option, ) -> TransactionReceiptInfo { TransactionReceiptInfo { tx_hash, @@ -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.map(|a| a.into()), - caller.into(), + transaction.tx.to, + caller, transaction.tx.data, Some(transaction.tx.gas_limit), Some(transaction.tx.value), @@ -213,13 +211,13 @@ 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 { - Some(EthereumAddress::from(s.to_string())) + 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]; diff --git a/src/kernel_evm/kernel/src/genesis.rs b/src/kernel_evm/kernel/src/genesis.rs index c7738120daec..115d427fdac5 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 8e8cd6c4f2b6..4b0e10611da6 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 e550e593faeb..5d9d87f98fc8 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.map(|addr| addr.into()), - e.caller()?.into(), + e.to, + e.caller()?, e.data, Some(e.gas_limit), Some(e.value), -- GitLab