Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
fix(core): add eip1559 prefix for sighash
Browse files Browse the repository at this point in the history
 - add a test which properly tests the `from` address decoding, which
   was incorrect due to the tx type not being hashed before recovery
  • Loading branch information
Rjected committed Apr 26, 2022
1 parent 9d53c73 commit b7e407d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 8 deletions.
14 changes: 10 additions & 4 deletions ethers-core/src/types/transaction/eip1559.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub struct Eip1559TransactionRequest {
}

impl Eip1559TransactionRequest {
/// EIP-2718 transaction type
const TX_TYPE: u8 = 0x02;

/// Creates an empty transaction request with all fields left empty
pub fn new() -> Self {
Self::default()
Expand Down Expand Up @@ -159,7 +162,10 @@ impl Eip1559TransactionRequest {

/// Hashes the transaction's data with the provided chain id
pub fn sighash(&self) -> H256 {
keccak256(self.rlp().as_ref()).into()
let mut encoded = vec![];
encoded.extend_from_slice(&[Self::TX_TYPE]);
encoded.extend_from_slice(self.rlp().as_ref());
keccak256(encoded).into()
}

/// Gets the unsigned transaction's RLP encoding
Expand Down Expand Up @@ -234,11 +240,11 @@ impl Eip1559TransactionRequest {
let mut offset = 0;
let mut txn = Self::decode_base_rlp(rlp, &mut offset)?;

let v = rlp.at(offset)?.as_val()?;
let v = rlp.val_at(offset)?;
offset += 1;
let r = rlp.at(offset)?.as_val()?;
let r = rlp.val_at(offset)?;
offset += 1;
let s = rlp.at(offset)?.as_val()?;
let s = rlp.val_at(offset)?;

let sig = Signature { r, s, v };
txn.from = Some(sig.recover(txn.sighash())?);
Expand Down
56 changes: 55 additions & 1 deletion ethers-core/src/types/transaction/eip2718.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ impl From<&Transaction> for TypedTransaction {

#[cfg(test)]
mod tests {
use hex::ToHex;
use rlp::Decodable;

use super::*;
Expand Down Expand Up @@ -501,7 +502,7 @@ mod tests {
#[test]
fn test_signed_tx_decode() {
let expected_tx = Eip1559TransactionRequest::new()
.from(Address::from_str("0x27519a1d088898e04b12f9fb9733267a5e61481e").unwrap())
.from(Address::from_str("0x1acadd971da208d25122b645b2ef879868a83e21").unwrap())
.chain_id(1u64)
.nonce(0u64)
.max_priority_fee_per_gas(413047990155u64)
Expand Down Expand Up @@ -553,4 +554,57 @@ mod tests {
let tx_rlp = rlp::Rlp::new(typed_tx_hex.as_slice());
TypedTransaction::decode(&tx_rlp).unwrap();
}

#[test]
fn test_signed_tx_decode_all_fields() {
let typed_tx_hex = hex::decode("02f90188052b85012a05f20085012a05f2148301b3cd8080b9012d608060405234801561001057600080fd5b5061010d806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063cfae3217146037578063f8a8fd6d146066575b600080fd5b604080518082019091526003815262676d2160e81b60208201525b604051605d91906085565b60405180910390f35b6040805180820190915260048152636f6f662160e01b60208201526052565b600060208083528351808285015260005b8181101560b0578581018301518582016040015282016096565b8181111560c1576000604083870101525b50601f01601f191692909201604001939250505056fea2646970667358221220f89093a9819ba5d2a3384305511d0945ea94f36a8aa162ab62921b3841fe3afd64736f6c634300080c0033c080a08085850e935fd6af9ace1b0343b9e21d2dcc7e914c36cce61a4e32756c785980a04c57c184d5096263df981cb8a2f2c7f81640792856909dbf3295a2b7a1dc4a55").unwrap();
let tx_rlp = rlp::Rlp::new(typed_tx_hex.as_slice());
let (tx, sig) = TypedTransaction::decode_signed(&tx_rlp).unwrap();

let tx = match tx {
TypedTransaction::Eip1559(tx) => tx,
_ => panic!("The raw bytes should decode to an EIP1559 tranaction"),
};

// pre-sighash fields - if a value here is incorrect it will show up before the sighash
// and from asserts fail
let data = Bytes::from_str("0x608060405234801561001057600080fd5b5061010d806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063cfae3217146037578063f8a8fd6d146066575b600080fd5b604080518082019091526003815262676d2160e81b60208201525b604051605d91906085565b60405180910390f35b6040805180820190915260048152636f6f662160e01b60208201526052565b600060208083528351808285015260005b8181101560b0578581018301518582016040015282016096565b8181111560c1576000604083870101525b50601f01601f191692909201604001939250505056fea2646970667358221220f89093a9819ba5d2a3384305511d0945ea94f36a8aa162ab62921b3841fe3afd64736f6c634300080c0033").unwrap();
assert_eq!(&data, tx.data.as_ref().unwrap());

let chain_id = U64::from(5u64);
assert_eq!(chain_id, tx.chain_id.unwrap());

let nonce = Some(43u64.into());
assert_eq!(nonce, tx.nonce);

let max_fee_per_gas = Some(5000000020u64.into());
assert_eq!(max_fee_per_gas, tx.max_fee_per_gas);

let max_priority_fee_per_gas = Some(5000000000u64.into());
assert_eq!(max_priority_fee_per_gas, tx.max_priority_fee_per_gas);

let gas = Some(111565u64.into());
assert_eq!(gas, tx.gas);

// empty fields
assert_eq!(None, tx.to);
assert_eq!(AccessList(vec![]), tx.access_list);

// compare rlp - sighash should then be the same
let tx_expected_rlp = "f90145052b85012a05f20085012a05f2148301b3cd8080b9012d608060405234801561001057600080fd5b5061010d806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063cfae3217146037578063f8a8fd6d146066575b600080fd5b604080518082019091526003815262676d2160e81b60208201525b604051605d91906085565b60405180910390f35b6040805180820190915260048152636f6f662160e01b60208201526052565b600060208083528351808285015260005b8181101560b0578581018301518582016040015282016096565b8181111560c1576000604083870101525b50601f01601f191692909201604001939250505056fea2646970667358221220f89093a9819ba5d2a3384305511d0945ea94f36a8aa162ab62921b3841fe3afd64736f6c634300080c0033c0";
let tx_real_rlp_vec = tx.rlp().to_vec();
let tx_real_rlp: String = tx_real_rlp_vec.encode_hex();
assert_eq!(tx_expected_rlp, tx_real_rlp);

let r = U256::from_str("0x8085850e935fd6af9ace1b0343b9e21d2dcc7e914c36cce61a4e32756c785980").unwrap();
let s = U256::from_str("0x4c57c184d5096263df981cb8a2f2c7f81640792856909dbf3295a2b7a1dc4a55").unwrap();
let v = 0;
assert_eq!(r, sig.r);
assert_eq!(s, sig.s);
assert_eq!(v, sig.v);

// finally check from
let addr = Address::from_str("0x216b32eCEbAe6aF164921D3943cd7A9634FcB199").unwrap();
assert_eq!(addr, tx.from.unwrap());
}
}
6 changes: 3 additions & 3 deletions ethers-core/src/types/transaction/eip2930.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ impl Eip2930TransactionRequest {
let mut offset = 0;
let mut txn = Self::decode_base_rlp(rlp, &mut offset)?;

let v = rlp.at(offset)?.as_val()?;
let v = rlp.val_at(offset)?;
// populate chainid from v
txn.tx.chain_id = extract_chain_id(v);
offset += 1;
let r = rlp.at(offset)?.as_val()?;
let r = rlp.val_at(offset)?;
offset += 1;
let s = rlp.at(offset)?.as_val()?;
let s = rlp.val_at(offset)?;

let sig = Signature { r, s, v };
Ok((txn, sig))
Expand Down

0 comments on commit b7e407d

Please sign in to comment.