Skip to content

Commit

Permalink
add more test
Browse files Browse the repository at this point in the history
  • Loading branch information
sudo-shashank committed Oct 17, 2024
1 parent db33f3d commit b827f0c
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 54 deletions.
22 changes: 18 additions & 4 deletions src/eth/eip_1559_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -140,8 +139,12 @@ impl EthEip1559TxArgs {
Ok(stream.out().to_vec())
}

pub fn get_signed_message(&self, from: Address) -> anyhow::Result<SignedMessage> {
ensure!(self.chain_id != EIP155_CHAIN_ID, "Invalid chain id");
pub fn get_signed_message(
&self,
from: Address,
eth_chain_id: EthChainId,
) -> anyhow::Result<SignedMessage> {
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,
Expand Down Expand Up @@ -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());
}
}
54 changes: 26 additions & 28 deletions src/eth/eip_155_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize> =
Lazy::new(|| calc_eip155_sig_len(EIP155_CHAIN_ID, 35) as usize);

pub static ETH_LEGACY_155_TX_SIGNATURE_LEN_1: Lazy<usize> =
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
Expand Down Expand Up @@ -50,9 +42,9 @@ pub struct EthLegacyEip155TxArgs {
}

impl EthLegacyEip155TxArgs {
pub fn signature(&self) -> anyhow::Result<Signature> {
pub fn signature(&self, eth_chain_id: EthChainId) -> anyhow::Result<Signature> {
// 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);
}

Expand All @@ -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
);
}
Expand All @@ -89,15 +80,18 @@ impl EthLegacyEip155TxArgs {
})
}

pub fn to_verifiable_signature(&self, mut sig: Vec<u8>) -> anyhow::Result<Vec<u8>> {
pub fn to_verifiable_signature(
&self,
mut sig: Vec<u8>,
eth_chain_id: EthChainId,
) -> anyhow::Result<Vec<u8>> {
// 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()
);
}
Expand All @@ -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);
Expand Down Expand Up @@ -217,7 +211,7 @@ impl EthLegacyEip155TxArgs {
Ok(stream.out().to_vec())
}

pub fn rlp_unsigned_message(&self) -> anyhow::Result<Vec<u8>> {
pub fn rlp_unsigned_message(&self, eth_chain_id: EthChainId) -> anyhow::Result<Vec<u8>> {
let mut stream = rlp::RlpStream::new();
stream
.begin_unbounded_list()
Expand All @@ -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<SignedMessage> {
pub fn get_signed_message(
&self,
from: Address,
eth_chain_id: EthChainId,
) -> anyhow::Result<SignedMessage> {
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)?;
Expand All @@ -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 })
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/eth/homestead_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ pub struct EthLegacyHomesteadTxArgs {
impl EthLegacyHomesteadTxArgs {
pub fn signature(&self) -> anyhow::Result<Signature> {
// 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");
}

Expand Down
64 changes: 46 additions & 18 deletions src/eth/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,21 @@ impl EthTx {
Ok(keccak_hash::keccak(self.rlp_signed_message()?))
}

pub fn get_signed_message(&self) -> anyhow::Result<SignedMessage> {
let from = self.sender()?;
pub fn get_signed_message(&self, eth_chain_id: EthChainId) -> anyhow::Result<SignedMessage> {
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<Vec<u8>> {
fn rlp_unsigned_message(&self, eth_chain_id: EthChainId) -> anyhow::Result<Vec<u8>> {
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),
}
}

Expand All @@ -137,19 +137,23 @@ impl EthTx {
}
}

fn signature(&self) -> anyhow::Result<Signature> {
fn signature(&self, eth_chain_id: EthChainId) -> anyhow::Result<Signature> {
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<u8>) -> anyhow::Result<Vec<u8>> {
fn to_verifiable_signature(
&self,
sig: Vec<u8>,
eth_chain_id: EthChainId,
) -> anyhow::Result<Vec<u8>> {
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),
}
}

Expand All @@ -176,10 +180,10 @@ impl EthTx {
Ok(())
}

fn sender(&self) -> anyhow::Result<Address> {
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<Address> {
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 =
Expand Down Expand Up @@ -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 _};
Expand Down Expand Up @@ -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",
)
Expand Down Expand Up @@ -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",
)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/methods/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2268,7 +2268,7 @@ impl RpcMethod<1> for EthSendRawTransaction {
(raw_tx,): Self::Params,
) -> Result<Self::Ok, ServerError> {
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())
}
Expand Down

0 comments on commit b827f0c

Please sign in to comment.