diff --git a/src/kernel_evm/Cargo.lock b/src/kernel_evm/Cargo.lock index 87418707c3197e4c7d47de6af133ee3f5e655a4e..5e3c3f90fe3034e6684babbe6ffd71d1675116e0 100644 --- a/src/kernel_evm/Cargo.lock +++ b/src/kernel_evm/Cargo.lock @@ -1525,6 +1525,7 @@ dependencies = [ "sha3", "tezos-smart-rollup-encoding", "tezos_crypto_rs", + "thiserror", ] [[package]] diff --git a/src/kernel_evm/ethereum/Cargo.toml b/src/kernel_evm/ethereum/Cargo.toml index 79a5b04321f18b21b76df6252d317e4ad8ae3123..b20233d210a28cc2acc511cf754a605358d5ce3c 100644 --- a/src/kernel_evm/ethereum/Cargo.toml +++ b/src/kernel_evm/ethereum/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" [dependencies] evm = { version = "0.35.0", default-features = false } +thiserror = "1.0" primitive-types = { version = "0.11.1", default-features = false } rlp = "0.5.2" hex = "0.4" diff --git a/src/kernel_evm/ethereum/src/signatures.rs b/src/kernel_evm/ethereum/src/signatures.rs index 0c7647dae96bd65be3a1ffdd362f5eb59ead27bd..821297a7a296dcdbdf63bd79abdba05cbc95ea98 100644 --- a/src/kernel_evm/ethereum/src/signatures.rs +++ b/src/kernel_evm/ethereum/src/signatures.rs @@ -9,7 +9,10 @@ //! We need to sign and write Ethereum specific values such //! as addresses and values. +use std::array::TryFromSliceError; + use crate::address::EthereumAddress; +use hex::FromHexError; use libsecp256k1::{ curve::Scalar, recover, sign, verify, Message, PublicKey, RecoveryId, SecretKey, Signature, @@ -17,16 +20,58 @@ use libsecp256k1::{ use primitive_types::{H256, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpIterator, RlpStream}; use sha3::{Digest, Keccak256}; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ParityError { + #[error("Couldn't reconstruct V from chain_id: {0}")] + ChainId(U256), + + #[error("Couldn't reconstruct parity from V: {0}")] + V(U256), +} +#[derive(Error, Debug, PartialEq)] +pub enum TransactionError { + #[error("Error reading a hex string: {0}")] + HexError(#[from] FromHexError), + + #[error("Error decoding RLP encoded byte array: {0}")] + DecoderError(#[from] DecoderError), + + #[error("Error extracting a slice")] + SlicingError, + #[error("Error manipulating ECDSA key: {0}")] + ECDSAError(libsecp256k1::Error), + + #[error("Error recomputing parity of signature: {0}")] + Parity(ParityError), +} + +impl From for TransactionError { + fn from(e: libsecp256k1::Error) -> Self { + Self::ECDSAError(e) + } +} + +impl From for TransactionError { + fn from(_: TryFromSliceError) -> Self { + Self::SlicingError + } +} /// produces address from a secret key -pub fn string_to_sk_and_address(s: String) -> (SecretKey, EthereumAddress) { - let data: [u8; 32] = hex::decode(s).unwrap().try_into().unwrap(); - let sk = SecretKey::parse(&data).unwrap(); +pub fn string_to_sk_and_address( + s: String, +) -> Result<(SecretKey, EthereumAddress), TransactionError> { + let mut data: [u8; 32] = [0u8; 32]; + hex::decode_to_slice(s, &mut data)?; + let sk = SecretKey::parse(&data)?; let pk = PublicKey::from_secret_key(&sk); let serialised = &pk.serialize()[1..]; let kec = Keccak256::digest(serialised); - let value: [u8; 20] = kec.as_slice()[12..].try_into().unwrap(); - (sk, EthereumAddress::from(value)) + let mut value: [u8; 20] = [0u8; 20]; + value.copy_from_slice(&kec[12..]); + Ok((sk, EthereumAddress::from(value))) } /// the type of a transaction @@ -95,8 +140,17 @@ impl EthereumTransactionCommon { Message::parse(&hash) } + /// recompute parity from v and chain_id + fn compute_parity(&self) -> Option { + let chain_id_encoding = self + .chain_id + .checked_mul(U256::from(2))? + .checked_add(U256::from(35))?; + self.v.checked_sub(chain_id_encoding) + } + /// Extracts the signature from an EthereumTransactionCommon - pub fn signature(&self) -> (Signature, RecoveryId) { + pub fn signature(&self) -> Result<(Signature, RecoveryId), TransactionError> { // copy r to Scalar let r: H256 = self.r; let r1: [u8; 32] = r.into(); @@ -108,61 +162,69 @@ impl EthereumTransactionCommon { let mut s = Scalar([0; 8]); let _ = s.set_b32(&s1); // recompute parity from v and chain_id - let ri = self.v - (self.chain_id * U256::from(2) + U256::from(35)); - if let Ok(ri) = RecoveryId::parse(ri.byte(0)) { - (Signature { r, s }, ri) - } else { - panic!( - "could not recompute parity from v={}, chain_id={}", - self.v, self.chain_id - ) - } + let ri_val = self + .compute_parity() + .ok_or(TransactionError::Parity(ParityError::V(self.v)))?; + let ri = RecoveryId::parse(ri_val.byte(0))?; + Ok((Signature { r, s }, ri)) } /// Find the caller address from r and s of the common data /// for an Ethereum transaction, ie, what address is associated /// with the signature of the message. /// TODO - pub fn caller(&self) -> EthereumAddress { + pub fn caller(&self) -> Result { let mes = self.message(); - let (sig, ri) = self.signature(); - let pk = recover(&mes, &sig, &ri).expect("Recover public key"); + let (sig, ri) = self.signature()?; + let pk = recover(&mes, &sig, &ri)?; let serialised = &pk.serialize()[1..]; let kec = Keccak256::digest(serialised); - let value: [u8; 20] = kec.as_slice()[12..] - .try_into() - .expect("Hash is 32 bytes, so [12..] should be 20 bytes long"); - EthereumAddress::from(value) + let value: [u8; 20] = kec.as_slice()[12..].try_into()?; + + Ok(EthereumAddress::from(value)) + } + + /// compute v from parity and chain_id + fn compute_v(&self, parity: u8) -> Option { + if self.chain_id == U256::zero() { + // parity is 0 or 1 + Some((27 + parity).into()) + } else { + let chain_id_encoding = self + .chain_id + .checked_mul(U256::from(2))? + .checked_add(U256::from(35))?; + U256::from(parity).checked_add(chain_id_encoding) + } } ///produce a signed EthereumTransactionCommon. If the initial one was signed /// you should get the same thing. - pub fn sign_transaction(&self, string_sk: String) -> Self { - let sk = SecretKey::parse_slice(&hex::decode(string_sk).unwrap()).unwrap(); + pub fn sign_transaction(&self, string_sk: String) -> Result { + let hex: &[u8] = &hex::decode(string_sk)?; + let sk = SecretKey::parse_slice(hex)?; let mes = self.message(); let (sig, ri) = sign(&mes, &sk); let Signature { r, s } = sig; let (r, s) = (H256::from(r.b32()), H256::from(s.b32())); let parity: u8 = ri.into(); - let v = if self.chain_id == U256::zero() { - (27 + parity).into() - } else { - U256::from(parity) + U256::from(2) * self.chain_id + U256::from(35) - }; - EthereumTransactionCommon { + let v = self.compute_v(parity).ok_or(TransactionError::Parity( + ParityError::ChainId(self.chain_id), + ))?; + Ok(EthereumTransactionCommon { v, r, s, ..self.clone() - } + }) } /// verifies the signature - pub fn verify_signature(self) -> bool { + pub fn verify_signature(self) -> Result { let mes = self.message(); - let (sig, ri) = self.signature(); - let pk = recover(&mes, &sig, &ri).unwrap(); - verify(&mes, &sig, &pk) + let (sig, ri) = self.signature()?; + let pk = recover(&mes, &sig, &ri)?; + Ok(verify(&mes, &sig, &pk)) } /// Unserialize bytes as a RLP encoded legacy transaction. @@ -318,6 +380,43 @@ impl Into> for EthereumTransactionCommon { mod test { use super::*; + // utility function to just build a standard correct transaction + // extracted from example in EIP 155 standard + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 + // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 + // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f + // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 + fn basic_eip155_transaction() -> EthereumTransactionCommon { + EthereumTransactionCommon { + chain_id: U256::one(), + nonce: U256::from(9), + gas_price: U256::from(20000000000u64), + gas_limit: U256::from(21000), + to: EthereumAddress::from( + "3535353535353535353535353535353535353535".to_string(), + ), + value: U256::from(1000000000000000000u64), + data: vec![], + v: U256::from(37), + r: string_to_h256_unsafe( + "28EF61340BD939BC2195FE537567866003E1A15D3C71FF63E1590620AA636276", + ), + s: string_to_h256_unsafe( + "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83", + ), + } + } + + fn basic_eip155_transaction_unsigned() -> EthereumTransactionCommon { + EthereumTransactionCommon { + v: U256::one(), + r: H256::zero(), + s: H256::zero(), + ..basic_eip155_transaction() + } + } + fn h256_to_string(e: H256) -> String { format!("{:x}", e) } @@ -373,133 +472,73 @@ mod test { #[test] fn test_caller_classic() { + // setup let (_sk, address_from_sk) = string_to_sk_and_address( "4646464646464646464646464646464646464646464646464646464646464646" .to_string(), - ); + ) + .unwrap(); let encoded = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83".to_string(); - let transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); - let address = transaction.caller(); + let expected_address_string: [u8; 20] = hex::decode("9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F") .unwrap() .try_into() .unwrap(); let expected_address = EthereumAddress::from(expected_address_string); + + // act + let transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); + let address = transaction.caller().unwrap(); + + // assert assert_eq!(expected_address, address); assert_eq!(expected_address, address_from_sk) } #[test] fn test_decoding_eip_155_example_unsigned() { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - // Consider a transaction with nonce = 9, gasprice = 20 * 10**9, startgas = 21000, to = 0x3535353535353535353535353535353535353535, value = 10**18, data='' (empty) - // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 - // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 - // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f - // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 - let nonce = U256::from(9); - let gas_price = U256::from(20000000000u64); - let gas_limit = U256::from(21000); - let to = - EthereumAddress::from("3535353535353535353535353535353535353535".to_string()); - assert_ne!( - to, - EthereumAddress::from_u64_be(0), - "making sure the expected address is correct" - ); - let value = U256::from(1000000000000000000u64); - let data: Vec = vec![]; - let chain_id = U256::one(); - let v = chain_id; - let expected_transaction = EthereumTransactionCommon { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - data, - v, - r: H256::zero(), - s: H256::zero(), - }; - // setup + let expected_transaction = basic_eip155_transaction_unsigned(); let signing_data = "ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080"; + + // act let tx = hex::decode(signing_data).unwrap(); let decoder = Rlp::new(&tx); - let decoded = EthereumTransactionCommon::decode(&decoder); assert!(decoded.is_ok(), "testing the decoding went ok"); + // assert let decoded_transaction = decoded.unwrap(); - assert_eq!(nonce, decoded_transaction.nonce, "testing nonce"); - assert_eq!( - gas_price, decoded_transaction.gas_price, - "testing gas price" - ); - assert_eq!( - gas_limit, decoded_transaction.gas_limit, - "testing gas limit" - ); - assert_eq!(to, decoded_transaction.to, "testing addresse"); - assert_eq!(value, decoded_transaction.value, "testing value"); - assert_eq!(Vec::::new(), decoded_transaction.data, "testing data"); - assert_eq!(U256::one(), decoded_transaction.v, "testing v"); - assert_eq!(H256::zero(), decoded_transaction.r, "testing r"); - assert_eq!(H256::zero(), decoded_transaction.s, "testing s"); assert_eq!(expected_transaction, decoded_transaction) } + #[test] fn test_decoding_leading0_signature() { // decoding of a transaction where r or s had some leading 0, which where deleted let signed_tx = "f888018506fc23ac00831000009412f142944da31ab85458787aaecaf5e34128619d80a40b7d796e0000000000000000000000000000000000000000000000000000000000000000269f75b1bc94b868a5a047470eae6008602e414d1471c2bbd14b37ffe56b1a85c9a001d9d58bb23af2090742aab9824c916fdc021a91f3e8d36571a5fc55547bc596"; + // act let tx = hex::decode(signed_tx).unwrap(); let decoder = Rlp::new(&tx); let decoded = EthereumTransactionCommon::decode(&decoder); + + // assert assert!(decoded.is_ok(), "testing the decoding went ok"); } + #[test] fn test_encoding_eip155_unsigned() { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - // Consider a transaction with nonce = 9, gasprice = 20 * 10**9, startgas = 21000, to = 0x3535353535353535353535353535353535353535, value = 10**18, data='' (empty) - // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 - // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 - // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f - // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 - let nonce = U256::from(9); - let gas_price = U256::from(20000000000u64); - let gas_limit = U256::from(21000); - let to = - EthereumAddress::from("3535353535353535353535353535353535353535".to_string()); - let value = U256::from(1000000000000000000u64); - let data: Vec = vec![]; - let chain_id = U256::one(); - let v = chain_id; - let expected_transaction = EthereumTransactionCommon { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - data, - v, - r: H256::zero(), - s: H256::zero(), - }; - // setup + let expected_transaction = basic_eip155_transaction_unsigned(); let signing_data = "ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080"; - let tx = hex::decode(signing_data).unwrap(); + + // act let encoded = expected_transaction.rlp_bytes(); + // assert assert_eq!(signing_data, hex::encode(&encoded)); - assert_eq!(tx, &encoded[..]); - assert_eq!(tx, encoded.to_vec()); } pub fn string_to_h256_unsafe(s: &str) -> H256 { @@ -510,6 +549,8 @@ mod test { #[test] fn test_encoding_create() { + // setup + // transaction "without to field" // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f @@ -541,56 +582,28 @@ mod test { s, }; - // setup let signed_tx = "f8572e8506c50218ba8304312280843b9aca0082ffff26a0e9637495be4c216a833ef390b1f6798917c8a102ab165c5085cced7ca1f2eb3aa057854e7044a8fee7bccb6a2c32c4229dd9cbacad74350789e0ce75bf40b6f713"; + // act let encoded = expected_transaction.rlp_bytes(); + // assert assert_eq!(signed_tx, hex::encode(&encoded)); } + #[test] fn test_encoding_eip155_signed() { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - // Consider a transaction with nonce = 9, gasprice = 20 * 10**9, startgas = 21000, to = 0x3535353535353535353535353535353535353535, value = 10**18, data='' (empty) - // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 - // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 - // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f - // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 - let nonce = U256::from(9); - let gas_price = U256::from(20000000000u64); - let gas_limit = U256::from(21000); - let to = - EthereumAddress::from("3535353535353535353535353535353535353535".to_string()); - let value = U256::from(1000000000000000000u64); - let data: Vec = vec![]; - let chain_id = U256::one(); - let v = U256::from(37); - let r = string_to_h256_unsafe( - "28EF61340BD939BC2195FE537567866003E1A15D3C71FF63E1590620AA636276", - ); - let s = string_to_h256_unsafe( - "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83", - ); - let expected_transaction = EthereumTransactionCommon { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - data, - v, - r, - s, - }; - // setup + let expected_transaction = basic_eip155_transaction(); let signed_tx = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83"; + // act let encoded = expected_transaction.rlp_bytes(); + // assert assert_eq!(signed_tx, hex::encode(&encoded)); } + #[test] fn test_decoding_arbitrary_signed() { // arbitrary transaction with data @@ -621,82 +634,31 @@ mod test { r, s, }; + let signed_data = "f90150808509502f900082520894423163e58aabec5daa3dd1130b759d24bef0f6ea8711c37937e08000b8e4deace8f5000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000041bca408a6b4029b42883aeb2c25087cab76cb58000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000002357a49c7d75f600000000000000000000000000000000000000000000000000000000640b5549000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000000025a025dd6c973368c45ddfc17f5148e3f468a2e3f2c51920cbe9556a64942b0ab2eba031da07ce40c24b0a01f46fb2abc028b5ccd70dbd1cb330725323edc49a2a9558"; // act - let signed_data = "f90150808509502f900082520894423163e58aabec5daa3dd1130b759d24bef0f6ea8711c37937e08000b8e4deace8f5000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000041bca408a6b4029b42883aeb2c25087cab76cb58000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000002357a49c7d75f600000000000000000000000000000000000000000000000000000000640b5549000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000000025a025dd6c973368c45ddfc17f5148e3f468a2e3f2c51920cbe9556a64942b0ab2eba031da07ce40c24b0a01f46fb2abc028b5ccd70dbd1cb330725323edc49a2a9558"; let tx = hex::decode(signed_data).unwrap(); let decoder = Rlp::new(&tx); - let decoded = EthereumTransactionCommon::decode(&decoder); // assert assert_eq!(Ok(expected_transaction), decoded) } + #[test] fn test_decoding_eip_155_example_signed() { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - // Consider a transaction with nonce = 9, gasprice = 20 * 10**9, startgas = 21000, to = 0x3535353535353535353535353535353535353535, value = 10**18, data='' (empty) - // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 - // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 - // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f - // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 - let nonce = U256::from(9); - let gas_price = U256::from(20000000000u64); - let gas_limit = U256::from(21000); - let to = - EthereumAddress::from("3535353535353535353535353535353535353535".to_string()); - assert_ne!( - to, - EthereumAddress::from_u64_be(0), - "making sure the expected address is correct" - ); - let value = U256::from(1000000000000000000u64); - let data: Vec = vec![]; - let v = U256::from(37); - let r = string_to_h256_unsafe( - "28EF61340BD939BC2195FE537567866003E1A15D3C71FF63E1590620AA636276", - ); - let s = string_to_h256_unsafe( - "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83", - ); - let expected_transaction = EthereumTransactionCommon { - chain_id: U256::one(), - nonce, - gas_price, - gas_limit, - to, - value, - data, - v, - r, - s, - }; - // setup + let expected_transaction = basic_eip155_transaction(); let signed_data = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83"; + + // act let tx = hex::decode(signed_data).unwrap(); let decoder = Rlp::new(&tx); - let decoded = EthereumTransactionCommon::decode(&decoder); - assert!(decoded.is_ok(), "testing the decoding went ok"); + // assert + assert!(decoded.is_ok(), "testing the decoding went ok"); let decoded_transaction = decoded.unwrap(); - assert_eq!(nonce, decoded_transaction.nonce, "testing nonce"); - assert_eq!( - gas_price, decoded_transaction.gas_price, - "testing gas price" - ); - assert_eq!( - gas_limit, decoded_transaction.gas_limit, - "testing gas limit" - ); - assert_eq!(to, decoded_transaction.to, "testing addresse"); - assert_eq!(value, decoded_transaction.value, "testing value"); - assert_eq!(Vec::::new(), decoded_transaction.data, "testing data"); - assert_eq!(U256::from(37), decoded_transaction.v, "testing v"); - assert_eq!(r, decoded_transaction.r, "testing r"); - assert_eq!(s, decoded_transaction.s, "testing s"); - assert_eq!(expected_transaction, decoded_transaction) } @@ -741,7 +703,6 @@ mod test { let signed_data = "f903732e8506c50218ba8304312294ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b880a8db2d41b89b009b903043593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000025a0c78be9ab81c622c08f7098eefc250935365fb794dfd94aec0fea16c32adec45aa05721614264d8490c6866f110c1594151bbcc4fac43758adae644db6bc3314d06"; let tx = hex::decode(signed_data).unwrap(); let decoder = Rlp::new(&tx); - let decoded = EthereumTransactionCommon::decode(&decoder); // assert @@ -784,12 +745,12 @@ mod test { r, s, }; - - // act let signed_data = "f903732e8506c50218ba8304312294ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b880a8db2d41b89b009b903043593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000025a0c78be9ab81c622c08f7098eefc250935365fb794dfd94aec0fea16c32adec45aa05721614264d8490c6866f110c1594151bbcc4fac43758adae644db6bc3314d06"; + // act let encoded = expected_transaction.rlp_bytes(); + // assert assert_eq!(signed_data, hex::encode(&encoded)); } @@ -827,14 +788,14 @@ mod test { "6053c1bd83abb30c109801844709202208736d598649afe2a53f024b61b3383f", ), }; + let signed_data = "f869018506fc23ac0083100000944e1b2c985d729ae6e05ef7974013eeb48f394449843b9aca008026a0bb03310570362eef497a09dd6e4ef42f56374965cfb09cc4e055a22a2eeac7ada06053c1bd83abb30c109801844709202208736d598649afe2a53f024b61b3383f"; // act - let signed_data = "f869018506fc23ac0083100000944e1b2c985d729ae6e05ef7974013eeb48f394449843b9aca008026a0bb03310570362eef497a09dd6e4ef42f56374965cfb09cc4e055a22a2eeac7ada06053c1bd83abb30c109801844709202208736d598649afe2a53f024b61b3383f"; let tx = hex::decode(signed_data).unwrap(); let decoder = Rlp::new(&tx); - let decoded = EthereumTransactionCommon::decode(&decoder); + // assert assert_eq!(Ok(expected_transaction), decoded); } @@ -874,11 +835,14 @@ mod test { // assert assert_eq!( - EthereumAddress::from("d9e5c94a12f78a96640757ac97ba0c257e8aa262".to_string()), + Ok(EthereumAddress::from( + "d9e5c94a12f78a96640757ac97ba0c257e8aa262".to_string() + )), transaction.caller(), "test field from" ) } + #[test] fn test_signature_ethereum_js() { // private key 0xcb9db6b5878db2fa20586e23b7f7b51c22a7c6ed0530daafc2615b116f170cd3 @@ -894,6 +858,7 @@ mod test { // s: 6053c1bd83abb30c109801844709202208736d598649afe2a53f024b61b3383f // tx: 0xf869018506fc23ac0083100000944e1b2c985d729ae6e05ef7974013eeb48f394449843b9aca008026a0bb03310570362eef497a09dd6e4ef42f56374965cfb09cc4e055a22a2eeac7ada06053c1bd83abb30c109801844709202208736d598649afe2a53f024b61b3383f + // setup let transaction = EthereumTransactionCommon { chain_id: U256::one(), nonce: U256::from(1), @@ -909,11 +874,15 @@ mod test { s: H256::zero(), }; - let signed = transaction.sign_transaction( - "cb9db6b5878db2fa20586e23b7f7b51c22a7c6ed0530daafc2615b116f170cd3" - .to_string(), - ); + // act + let signed = transaction + .sign_transaction( + "cb9db6b5878db2fa20586e23b7f7b51c22a7c6ed0530daafc2615b116f170cd3" + .to_string(), + ) + .unwrap(); + // assert let v = U256::from(38); let r = string_to_h256_unsafe( "bb03310570362eef497a09dd6e4ef42f56374965cfb09cc4e055a22a2eeac7ad", @@ -931,7 +900,7 @@ mod test { fn test_caller_classic_with_chain_id() { let sk = "9bfc9fbe6296c8fef8eb8d6ce2ed5f772a011898c6cabe32d35e7c3e419efb1b" .to_string(); - let (_sk, address) = string_to_sk_and_address(sk.clone()); + 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") @@ -944,44 +913,20 @@ mod test { // Check that the derived sender address is the expected one. let encoded = "f86d80843b9aca00825208940b52d4d3be5d18a7ab5e4476a2f5382bbf2b38d888016345785d8a000080820a95a0d9ef1298c18c88604e3f08e14907a17dfa81b1dc6b37948abe189d8db5cb8a43a06fc7040a71d71d3cb74bd05ead7046b10668ad255da60391c017eea31555f156".to_string(); let transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); - let address = transaction.caller(); + let address = transaction.caller().unwrap(); assert_eq!(expected_address, address); // Check that signing the signed transaction returns the same transaction. let signed_transaction = transaction.sign_transaction(sk); - assert_eq!(transaction, signed_transaction) + assert_eq!(transaction, signed_transaction.unwrap()) } #[test] - fn test_call_eip155_example() { - // example directly lifted from eip155 description - // signing data 0xec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080 - // private key : 0x4646464646464646464646464646464646464646464646464646464646464646 - // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f - // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 let nonce = U256::from(9); - - let transaction = EthereumTransactionCommon { - chain_id: U256::one(), - nonce: U256::from(9), - gas_price: U256::from(20000000000u64), - gas_limit: U256::from(21000), - to: EthereumAddress::from( - "3535353535353535353535353535353535353535".to_string(), - ), - value: U256::from(1000000000000000000u64), - data: vec![], - v: U256::from(37), - r: string_to_h256_unsafe( - "28EF61340BD939BC2195FE537567866003E1A15D3C71FF63E1590620AA636276", - ), - s: string_to_h256_unsafe( - "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83", - ), - }; - + fn test_caller_eip155_example() { + let transaction = basic_eip155_transaction(); assert_eq!( EthereumAddress::from("9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f".to_string()), - transaction.caller() + transaction.caller().unwrap() ) } @@ -989,6 +934,7 @@ mod test { fn test_caller_uniswap_inspired() { // inspired by 0xf598016f51e0544187088ddd50fd37818fd268a0363a17281576425f3ee334cb + // setup let data: Vec = hex::decode("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000").unwrap(); let transaction = EthereumTransactionCommon { @@ -1009,8 +955,12 @@ mod test { "5721614264d8490c6866f110c1594151bbcc4fac43758adae644db6bc3314d06", ), }; + + // check assert_eq!( - EthereumAddress::from("af1276cbb260bb13deddb4209ae99ae6e497f446".to_string()), + Ok(EthereumAddress::from( + "af1276cbb260bb13deddb4209ae99ae6e497f446".to_string() + )), transaction.caller(), "checking caller" ) @@ -1020,6 +970,7 @@ mod test { fn test_message_uniswap_inspired() { // inspired by 0xf598016f51e0544187088ddd50fd37818fd268a0363a17281576425f3ee334cb + // setup let data: Vec = hex::decode("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064023c1700000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a8db2d41b89b009000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000002ab0c205a56c1e000000000000000000000000000000000000000000000000000000a8db2d41b89b00900000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009eb6299e4bb6669e42cb295a254c8492f67ae2c6000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000").unwrap(); let transaction = EthereumTransactionCommon { @@ -1037,6 +988,7 @@ mod test { s: H256::zero(), }; + // check assert_eq!( Message::parse_slice( &hex::decode( @@ -1072,11 +1024,14 @@ mod test { }; // act - let signed = transaction.sign_transaction( - "dcdff53b4f013dbcdc717f89fe3bf4d8b10512aae282b48e01d7530470382701" - .to_string(), - ); + let signed = transaction + .sign_transaction( + "dcdff53b4f013dbcdc717f89fe3bf4d8b10512aae282b48e01d7530470382701" + .to_string(), + ) + .unwrap(); + // assert let v = U256::from(37); let r = string_to_h256_unsafe( "c78be9ab81c622c08f7098eefc250935365fb794dfd94aec0fea16c32adec45a", @@ -1098,36 +1053,18 @@ mod test { // corresponding address 0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f // signed tx : 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 let nonce = U256::from(9); - let transaction = EthereumTransactionCommon { - chain_id: U256::one(), - nonce: U256::from(9), - gas_price: U256::from(20000000000u64), - gas_limit: U256::from(21000), - to: EthereumAddress::from( - "3535353535353535353535353535353535353535".to_string(), - ), - value: U256::from(1000000000000000000u64), - data: vec![], - v: U256::one(), - r: H256::zero(), - s: H256::zero(), - }; - let v = U256::from(37); - let r = string_to_h256_unsafe( - "28EF61340BD939BC2195FE537567866003E1A15D3C71FF63E1590620AA636276", - ); - let s = string_to_h256_unsafe( - "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83", - ); + // setup + let transaction = basic_eip155_transaction_unsigned(); + let expected_signed = basic_eip155_transaction(); + // act let signed = transaction.sign_transaction( "4646464646464646464646464646464646464646464646464646464646464646" .to_string(), ); - assert_eq!(v, signed.v, "checking v"); - assert_eq!(r, signed.r, "checking r"); - assert_eq!(s, signed.s, "checking s"); + // assert + assert_eq!(Ok(expected_signed), signed, "checking signed transaction") } #[test] @@ -1142,4 +1079,133 @@ mod test { assert_eq!(hex::encode(&encoded), *str); }); } + + #[test] + fn test_decoding_not_eip_155_fails_gracefully() { + // decoding of a transaction that is not eip 155, ie v = 28 / 27 + // initial transaction: + // { + // "nonce": "0x0", + // "gasPrice": "0x10000000000", + // "gasLimit": "0x25000", + // "value": "0x0", + // "data": "0x608060405234801561001057600080fd5b50602a600081905550610150806100286000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea26469706673582212204d6c1853cec27824f5dbf8bcd0994714258d22fc0e0dc8a2460d87c70e3e57a564736f6c63430008120033", + // "chainId": 0 + // } + // private key: 0xe75f4c63daecfbb5be03f65940257f5b15e440e6cf26faa126ce68741d5d0f78 + // caller address: 0x3dbeca6e9a6f0677e3c7b5946fc8adbb1b071e0a + + // setup + let signed_tx = "f901cc8086010000000000830250008080b90178608060405234801561001057600080fd5b50602a600081905550610150806100286000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea26469706673582212204d6c1853cec27824f5dbf8bcd0994714258d22fc0e0dc8a2460d87c70e3e57a564736f6c634300081200331ca06d851632958801b6919ba534b4b1feb1bdfaabd0d42890bce200a11ac735d58da0219b058d7169d7a4839c5cdd555b0820b545797365287a81ba409419912de7b1"; + let r = string_to_h256_unsafe( + "6d851632958801b6919ba534b4b1feb1bdfaabd0d42890bce200a11ac735d58d", + ); + let s = string_to_h256_unsafe( + "219b058d7169d7a4839c5cdd555b0820b545797365287a81ba409419912de7b1", + ); + + // act + let tx = hex::decode(signed_tx).unwrap(); + let decoder = Rlp::new(&tx); + let decoded = EthereumTransactionCommon::decode(&decoder); + + // sanity check + assert!(decoded.is_ok(), "testing the decoding went ok"); + let decoded_transaction = decoded.unwrap(); + assert_eq!(U256::from(28), decoded_transaction.v, "testing v"); + assert_eq!(r, decoded_transaction.r, "testing r"); + assert_eq!(s, decoded_transaction.s, "testing s"); + + // check signature fails gracefully + assert!( + decoded_transaction.signature().is_err(), + "testing signature" + ); + assert!(decoded_transaction.caller().is_err(), "testing caller"); + } + + #[test] + fn test_signature_unsigned_fails_gracefully() { + // most data is not relevant here, the point is to test failure mode of signature verification + let transaction = EthereumTransactionCommon { + v: U256::one(), // parity is not consistent with a signed transaction + ..basic_eip155_transaction() + }; + + // check signature fails gracefully + assert!(transaction.signature().is_err(), "testing invalid parity"); + } + + #[test] + fn test_signature_invalid_signature_fails_gracefully() { + // most data is not relevant here, the point is to test failure mode of signature verification + let transaction = EthereumTransactionCommon { + v: U256::from(38), // parity is consistent with a signed transaction + r: H256::zero(), // signature value is wrong + ..basic_eip155_transaction() + }; + + // sanity check + assert!( + transaction.signature().is_ok(), + "testing signature is well formed" + ); + + // check caller fails gracefully + assert!( + transaction.caller().is_err(), + "testing caller fails, because signature is useless" + ); + } + + #[test] + fn test_signature_invalid_parity_fails_gracefully() { + // most data is not relevant here, the point is to test failure mode of signature verification + let transaction = EthereumTransactionCommon { + v: U256::from(150), // parity is not consistent with chain_id + chain_id: U256::one(), + ..basic_eip155_transaction() + }; + + // check signature fails gracefully + assert!( + transaction.signature().is_err(), + "testing signature checking fails gracefully" + ); + } + + #[test] + fn test_signature_invalid_chain_id_fails_gracefully() { + // most data is not relevant here, the point is to test failure mode of signature verification + let transaction = EthereumTransactionCommon { + chain_id: U256::max_value(), // chain_id will overflow parity computation + ..basic_eip155_transaction() + }; + + // check signature fails gracefully + assert!( + transaction.signature().is_err(), + "testing signature checking fails gracefully" + ); + } + + #[test] + fn test_sign_invalid_chain_id_fails_gracefully() { + // most data is not relevant here, the point is to test failure mode of signature verification + let transaction = EthereumTransactionCommon { + chain_id: U256::max_value(), + ..basic_eip155_transaction_unsigned() + }; + + // check signature fails gracefully + assert!( + transaction + .sign_transaction( + "4646464646464646464646464646464646464646464646464646464646464646" + .to_string() + ) + .is_err(), + "testing signature fails gracefully" + ); + } } diff --git a/src/kernel_evm/evm_execution/src/lib.rs b/src/kernel_evm/evm_execution/src/lib.rs index 1b34a5cd999034e4783c1bd899ef3b15b30e74c7..1011a16567013163b890163461c30a1be30ac25a 100644 --- a/src/kernel_evm/evm_execution/src/lib.rs +++ b/src/kernel_evm/evm_execution/src/lib.rs @@ -476,7 +476,8 @@ mod test { let (sk, _address) = tezos_ethereum::signatures::string_to_sk_and_address( "4646464646464646464646464646464646464646464646464646464646464646" .to_string(), - ); + ) + .unwrap(); let m: [u8; 32] = hex::decode( "daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53", ) @@ -514,7 +515,8 @@ mod test { ]; test_list.iter().fold((), |_, (s, ea)| { let (_, a) = - tezos_ethereum::signatures::string_to_sk_and_address(s.to_string()); + 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); assert_eq!(a, ea); @@ -523,14 +525,16 @@ mod test { #[test] fn test_caller_classic() { - let (_sk, address_from_sk) = tezos_ethereum::signatures::string_to_sk_and_address( - "4646464646464646464646464646464646464646464646464646464646464646" - .to_string(), - ); + let (_sk, address_from_sk) = + tezos_ethereum::signatures::string_to_sk_and_address( + "4646464646464646464646464646464646464646464646464646464646464646" + .to_string(), + ) + .unwrap(); let encoded = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83".to_string(); let transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); - let address = transaction.caller(); + let address = transaction.caller().unwrap(); let expected_address_string: [u8; 20] = hex::decode("9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F") .unwrap() @@ -550,7 +554,7 @@ mod test { "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83".to_string(); let expected_transaction = EthereumTransactionCommon::from_rlp(encoded).unwrap(); - let transaction = expected_transaction.sign_transaction(string_sk); + let transaction = expected_transaction.sign_transaction(string_sk).unwrap(); assert_eq!(expected_transaction, transaction) } diff --git a/src/kernel_evm/kernel/src/block.rs b/src/kernel_evm/kernel/src/block.rs index 1c17262103bc0f7f4a9b315ff329b09b786bc2ea..29b3ff72379d4665ba983155ec65f3b0f7a54e53 100644 --- a/src/kernel_evm/kernel/src/block.rs +++ b/src/kernel_evm/kernel/src/block.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use crate::blueprint::Queue; -use crate::error::Error; +use crate::error::{Error, TransferError}; use crate::helpers::address_to_hash; use crate::inbox::Transaction; use crate::storage; @@ -90,7 +90,9 @@ impl L2Block { fn get_tx_sender( tx: &EthereumTransactionCommon, ) -> Result<(OwnedPath, EthereumAddress), Error> { - let address = tx.caller(); + let address = tx + .caller() + .or(Err(Error::Transfer(TransferError::InvalidSignature)))?; // We reencode in hexadecimal, since the accounts hash are encoded in // hexadecimal in the storage. let hash = address_to_hash(address); @@ -170,7 +172,7 @@ fn apply_transaction( if sender_balance < value || sender_nonce != transaction.tx.nonce - || !transaction.tx.clone().verify_signature() + || transaction.tx.clone().verify_signature().is_err() { Ok(make_receipt( block,