From b827f0c85ba760724bc2f2643a5c0284650ec65c Mon Sep 17 00:00:00 2001 From: sudo-shashank Date: Thu, 17 Oct 2024 15:31:41 +0530 Subject: [PATCH] add more test --- src/eth/eip_1559_transaction.rs | 22 +++++++++-- src/eth/eip_155_transaction.rs | 54 +++++++++++++-------------- src/eth/homestead_transaction.rs | 4 +- src/eth/transaction.rs | 64 +++++++++++++++++++++++--------- src/rpc/methods/eth.rs | 2 +- 5 files changed, 92 insertions(+), 54 deletions(-) diff --git a/src/eth/eip_1559_transaction.rs b/src/eth/eip_1559_transaction.rs index df564416371..1e63dd6a272 100644 --- a/src/eth/eip_1559_transaction.rs +++ b/src/eth/eip_1559_transaction.rs @@ -7,9 +7,8 @@ use crate::message::SignedMessage; use crate::shim::address::Address; use crate::shim::crypto::SignatureType::Delegated; -use anyhow::bail; -use anyhow::ensure; use anyhow::Context; +use anyhow::{bail, ensure}; use derive_builder::Builder; use num::BigInt; use num_bigint::Sign; @@ -140,8 +139,12 @@ impl EthEip1559TxArgs { Ok(stream.out().to_vec()) } - pub fn get_signed_message(&self, from: Address) -> anyhow::Result { - ensure!(self.chain_id != EIP155_CHAIN_ID, "Invalid chain id"); + pub fn get_signed_message( + &self, + from: Address, + eth_chain_id: EthChainId, + ) -> anyhow::Result { + ensure!(self.chain_id != eth_chain_id, "Invalid chain id"); let method_info = get_filecoin_method_info(&self.to, &self.input)?; let message = Message { version: 0, @@ -220,4 +223,15 @@ mod tests { let signature = Signature::new(SignatureType::Delegated, vec![0u8; EIP_1559_SIG_LEN - 1]); assert!(args.with_signature(&signature).is_err()); } + + #[test] + fn test_signature() { + let args = create_eip1559_tx_args(); + let signature = Signature::new(SignatureType::Delegated, vec![0u8; EIP_1559_SIG_LEN]); + args.clone().with_signature(&signature).unwrap(); + + let sig = args.signature().unwrap(); + assert_eq!(sig, signature); + assert!(args.to_verifiable_signature(sig.bytes().to_vec()).is_ok()); + } } diff --git a/src/eth/eip_155_transaction.rs b/src/eth/eip_155_transaction.rs index 3d07bbe5c27..0f454632fc9 100644 --- a/src/eth/eip_155_transaction.rs +++ b/src/eth/eip_155_transaction.rs @@ -12,17 +12,9 @@ use num_bigint::Sign; use num_bigint::ToBigInt; use num_traits::cast::ToPrimitive; use num_traits::FromPrimitive; -use once_cell::sync::Lazy; use std::ops::Mul; pub const EIP_155_SIG_PREFIX: u8 = 0x02; -pub const EIP155_CHAIN_ID: EthChainId = 314159; - -pub static ETH_LEGACY_155_TX_SIGNATURE_LEN_0: Lazy = - Lazy::new(|| calc_eip155_sig_len(EIP155_CHAIN_ID, 35) as usize); - -pub static ETH_LEGACY_155_TX_SIGNATURE_LEN_1: Lazy = - Lazy::new(|| calc_eip155_sig_len(EIP155_CHAIN_ID, 36) as usize); /// Description from Lotus: /// [`EthLegacyEip155TxArgs`] is a legacy Ethereum transaction that uses the EIP-155 chain replay protection mechanism @@ -50,9 +42,9 @@ pub struct EthLegacyEip155TxArgs { } impl EthLegacyEip155TxArgs { - pub fn signature(&self) -> anyhow::Result { + pub fn signature(&self, eth_chain_id: EthChainId) -> anyhow::Result { // Validate EIP155 Chain ID - if let Err(err) = validate_eip155_chain_id(EIP155_CHAIN_ID, &self.v) { + if let Err(err) = validate_eip155_chain_id(eth_chain_id, &self.v) { bail!("failed to validate EIP155 chain id: {}", err); } @@ -71,14 +63,13 @@ impl EthLegacyEip155TxArgs { sig.insert(0, EIP_155_SIG_PREFIX); // Check if signature length is correct + let valid_sig_len = calc_valid_eip155_sig_len(self.chain_id); let sig_len = sig.len(); - if sig_len != *ETH_LEGACY_155_TX_SIGNATURE_LEN_0 - && sig_len != *ETH_LEGACY_155_TX_SIGNATURE_LEN_1 - { + if sig_len != valid_sig_len.0 as usize && sig_len != valid_sig_len.1 as usize { bail!( "signature is not {:#?} OR {:#?} bytes; it is {} bytes", - ETH_LEGACY_155_TX_SIGNATURE_LEN_0, - ETH_LEGACY_155_TX_SIGNATURE_LEN_1, + valid_sig_len.0, + valid_sig_len.1, sig_len ); } @@ -89,15 +80,18 @@ impl EthLegacyEip155TxArgs { }) } - pub fn to_verifiable_signature(&self, mut sig: Vec) -> anyhow::Result> { + pub fn to_verifiable_signature( + &self, + mut sig: Vec, + eth_chain_id: EthChainId, + ) -> anyhow::Result> { // Check if the signature length is correct - if sig.len() != *ETH_LEGACY_155_TX_SIGNATURE_LEN_0 - && sig.len() != *ETH_LEGACY_155_TX_SIGNATURE_LEN_1 - { + let valid_sig_len = calc_valid_eip155_sig_len(self.chain_id); + if sig.len() != valid_sig_len.0 as usize && sig.len() != valid_sig_len.1 as usize { bail!( "signature should be {} or {} bytes long (1 byte metadata and rest bytes are sig data), but got {} bytes", - *ETH_LEGACY_155_TX_SIGNATURE_LEN_0, - *ETH_LEGACY_155_TX_SIGNATURE_LEN_1, + valid_sig_len.0, + valid_sig_len.1, sig.len() ); } @@ -121,11 +115,11 @@ impl EthLegacyEip155TxArgs { ); ensure!( - validate_eip155_chain_id(EIP155_CHAIN_ID, &v_value).is_ok(), + validate_eip155_chain_id(eth_chain_id, &v_value).is_ok(), "Invalid chain Id" ); - let chain_id_mul = BigInt::from(EIP155_CHAIN_ID) + let chain_id_mul = BigInt::from(eth_chain_id) .mul(2_i32.to_bigint().context("Failed to convert 2 to BigInt")?); v_value -= chain_id_mul; v_value -= BigInt::from(8); @@ -217,7 +211,7 @@ impl EthLegacyEip155TxArgs { Ok(stream.out().to_vec()) } - pub fn rlp_unsigned_message(&self) -> anyhow::Result> { + pub fn rlp_unsigned_message(&self, eth_chain_id: EthChainId) -> anyhow::Result> { let mut stream = rlp::RlpStream::new(); stream .begin_unbounded_list() @@ -227,16 +221,20 @@ impl EthLegacyEip155TxArgs { .append(&format_address(&self.to)) .append(&format_bigint(&self.value)?) .append(&self.input) - .append(&format_bigint(&BigInt::from(EIP155_CHAIN_ID))?) + .append(&format_bigint(&BigInt::from(eth_chain_id))?) .append(&format_u64(0)) .append(&format_u64(0)) .finalize_unbounded_list(); Ok(stream.out().to_vec()) } - pub fn get_signed_message(&self, from: Address) -> anyhow::Result { + pub fn get_signed_message( + &self, + from: Address, + eth_chain_id: EthChainId, + ) -> anyhow::Result { ensure!( - validate_eip155_chain_id(EIP155_CHAIN_ID, &self.v).is_ok(), + validate_eip155_chain_id(eth_chain_id, &self.v).is_ok(), "Failed to validate EIP155 chain Id" ); let method_info = get_filecoin_method_info(&self.to, &self.input)?; @@ -252,7 +250,7 @@ impl EthLegacyEip155TxArgs { gas_fee_cap: self.gas_price.clone().into(), gas_premium: self.gas_price.clone().into(), }; - let signature = self.signature()?; + let signature = self.signature(eth_chain_id)?; Ok(SignedMessage { message, signature }) } } diff --git a/src/eth/homestead_transaction.rs b/src/eth/homestead_transaction.rs index c151b2fa857..542c9ce10af 100644 --- a/src/eth/homestead_transaction.rs +++ b/src/eth/homestead_transaction.rs @@ -35,9 +35,7 @@ pub struct EthLegacyHomesteadTxArgs { impl EthLegacyHomesteadTxArgs { pub fn signature(&self) -> anyhow::Result { // Check if v is either 27 or 28 - let v27 = BigInt::from(27); - let v28 = BigInt::from(28); - if self.v != v27 && self.v != v28 { + if self.v != BigInt::from(27) && self.v != BigInt::from(28) { bail!("legacy homestead transactions only support 27 or 28 for v"); } diff --git a/src/eth/transaction.rs b/src/eth/transaction.rs index 5dbdd4b5657..61314fbd2cf 100644 --- a/src/eth/transaction.rs +++ b/src/eth/transaction.rs @@ -111,21 +111,21 @@ impl EthTx { Ok(keccak_hash::keccak(self.rlp_signed_message()?)) } - pub fn get_signed_message(&self) -> anyhow::Result { - let from = self.sender()?; + pub fn get_signed_message(&self, eth_chain_id: EthChainId) -> anyhow::Result { + let from = self.sender(eth_chain_id)?; let msg = match self { Self::Homestead(tx) => (*tx).get_signed_message(from)?, - Self::Eip1559(tx) => (*tx).get_signed_message(from)?, - Self::Eip155(tx) => (*tx).get_signed_message(from)?, + Self::Eip1559(tx) => (*tx).get_signed_message(from, eth_chain_id)?, + Self::Eip155(tx) => (*tx).get_signed_message(from, eth_chain_id)?, }; Ok(msg) } - fn rlp_unsigned_message(&self) -> anyhow::Result> { + fn rlp_unsigned_message(&self, eth_chain_id: EthChainId) -> anyhow::Result> { match self { Self::Homestead(tx) => (*tx).rlp_unsigned_message(), Self::Eip1559(tx) => (*tx).rlp_unsigned_message(), - Self::Eip155(tx) => (*tx).rlp_unsigned_message(), + Self::Eip155(tx) => (*tx).rlp_unsigned_message(eth_chain_id), } } @@ -137,19 +137,23 @@ impl EthTx { } } - fn signature(&self) -> anyhow::Result { + fn signature(&self, eth_chain_id: EthChainId) -> anyhow::Result { match self { Self::Homestead(tx) => (*tx).signature(), Self::Eip1559(tx) => (*tx).signature(), - Self::Eip155(tx) => (*tx).signature(), + Self::Eip155(tx) => (*tx).signature(eth_chain_id), } } - fn to_verifiable_signature(&self, sig: Vec) -> anyhow::Result> { + fn to_verifiable_signature( + &self, + sig: Vec, + eth_chain_id: EthChainId, + ) -> anyhow::Result> { match self { Self::Homestead(tx) => (*tx).to_verifiable_signature(sig), Self::Eip1559(tx) => (*tx).to_verifiable_signature(sig), - Self::Eip155(tx) => (*tx).to_verifiable_signature(sig), + Self::Eip155(tx) => (*tx).to_verifiable_signature(sig, eth_chain_id), } } @@ -176,10 +180,10 @@ impl EthTx { Ok(()) } - fn sender(&self) -> anyhow::Result
{ - let hash = keccak_hash::keccak(self.rlp_unsigned_message()?); - let sig = self.signature()?; - let sig_data = self.to_verifiable_signature(sig.bytes().to_vec())?[..] + fn sender(&self, eth_chain_id: EthChainId) -> anyhow::Result
{ + let hash = keccak_hash::keccak(self.rlp_unsigned_message(eth_chain_id)?); + let sig = self.signature(eth_chain_id)?; + let sig_data = self.to_verifiable_signature(sig.bytes().to_vec(), eth_chain_id)?[..] .try_into() .expect("Incorrect signature length"); let pubkey = @@ -473,7 +477,7 @@ pub fn get_filecoin_method_info( pub(crate) mod tests { use super::*; use crate::{ - networks::mainnet, + networks::{calibnet, mainnet}, shim::{crypto::Signature, econ::TokenAmount}, }; use num::{traits::FromBytes as _, BigInt, Num as _, Zero as _}; @@ -730,6 +734,13 @@ pub(crate) mod tests { ) .unwrap(); let tx = EthTx::Eip1559(Box::new(tx_args)); + let sig = tx.signature(mainnet::ETH_CHAIN_ID); + assert!(sig.is_ok()); + assert!(tx + .to_verifiable_signature(sig.unwrap().bytes().to_vec(), mainnet::ETH_CHAIN_ID) + .is_ok()); + assert!(tx.rlp_unsigned_message(mainnet::ETH_CHAIN_ID).is_ok()); + assert!(tx.get_signed_message(mainnet::ETH_CHAIN_ID).is_ok()); let expected_hash = ethereum_types::H256::from_str( "0x9f2e70d5737c6b798eccea14895893fb48091ab3c59d0fe95508dc7efdae2e5f", ) @@ -766,6 +777,13 @@ pub(crate) mod tests { ) .unwrap(); let tx = EthTx::Eip155(Box::new(tx_args)); + let sig = tx.signature(calibnet::ETH_CHAIN_ID); + assert!(sig.is_ok()); + assert!(tx + .to_verifiable_signature(sig.unwrap().bytes().to_vec(), calibnet::ETH_CHAIN_ID) + .is_ok()); + assert!(tx.rlp_unsigned_message(calibnet::ETH_CHAIN_ID).is_ok()); + assert!(tx.get_signed_message(calibnet::ETH_CHAIN_ID).is_ok()); let expected_hash = ethereum_types::H256::from_str( "0x3ebc897150feeff6caa1b2e5992e347e8409e9e35fa30f7f5f8fcda3f7c965c7", ) @@ -802,12 +820,22 @@ pub(crate) mod tests { 16, ) .unwrap(); - let tx = EthTx::Homestead(Box::new(tx_args)); + let tx = EthTx::Homestead(Box::new(tx_args.clone())); let expected_hash = ethereum_types::H256::from_str( "0x3ebc897150feeff6caa1b2e5992e347e8409e9e35fa30f7f5f8fcda3f7c965c7", ) .unwrap(); assert_eq!(expected_hash, tx.eth_hash().unwrap()); + // Note: `v` value 27 is for homestead + tx_args.v = BigInt::from_str_radix("1b", 16).unwrap(); + let tx = EthTx::Homestead(Box::new(tx_args.clone())); + let sig = tx.signature(calibnet::ETH_CHAIN_ID); + assert!(sig.is_ok()); + assert!(tx + .to_verifiable_signature(sig.unwrap().bytes().to_vec(), calibnet::ETH_CHAIN_ID) + .is_ok()); + assert!(tx.rlp_unsigned_message(calibnet::ETH_CHAIN_ID).is_ok()); + assert!(tx.get_signed_message(calibnet::ETH_CHAIN_ID).is_ok()); } #[quickcheck] @@ -901,7 +929,7 @@ pub(crate) mod tests { ) .expect("Invalid hex"); let eth_tx = parse_eth_transaction(&raw_tx).unwrap(); - let from = eth_tx.sender().unwrap(); + let from = eth_tx.sender(calibnet::ETH_CHAIN_ID).unwrap(); assert_eq!( EthAddress::from_filecoin_address(&from).unwrap(), EthAddress::from_str("0xEb1D0C87B7e33D0Ab44a397b675F0897295491C2").unwrap() @@ -913,7 +941,7 @@ pub(crate) mod tests { ) .expect("Invalid hex"); let eth_tx = parse_eth_transaction(&raw_tx).unwrap(); - let from = eth_tx.sender().unwrap(); + let from = eth_tx.sender(calibnet::ETH_CHAIN_ID).unwrap(); assert_eq!( EthAddress::from_filecoin_address(&from).unwrap(), EthAddress::from_str("0x4fda4174D5D07C906395bfB77806287cc65Fd129").unwrap() diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 57aca039eb0..5c62b7b489b 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -2268,7 +2268,7 @@ impl RpcMethod<1> for EthSendRawTransaction { (raw_tx,): Self::Params, ) -> Result { let tx_args = parse_eth_transaction(&raw_tx.0)?; - let smsg = tx_args.get_signed_message()?; + let smsg = tx_args.get_signed_message(ctx.chain_config().eth_chain_id)?; let cid = ctx.mpool.as_ref().push(smsg).await?; Ok(cid.into()) }