Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 140 additions & 1 deletion src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use sha3::{Digest, Keccak256};
use crate::{
enveloped::{EnvelopedDecodable, EnvelopedEncodable},
header::{Header, PartialHeader},
transaction::{TransactionAny, TransactionV0, TransactionV1, TransactionV2},
transaction::{TransactionAny, TransactionV0, TransactionV1, TransactionV2, TransactionV3},
util::ordered_trie_root,
};

Expand Down Expand Up @@ -76,6 +76,7 @@ impl<T: EnvelopedEncodable> Block<T> {
pub type BlockV0 = Block<TransactionV0>;
pub type BlockV1 = Block<TransactionV1>;
pub type BlockV2 = Block<TransactionV2>;
pub type BlockV3 = Block<TransactionV3>;
pub type BlockAny = Block<TransactionAny>;

impl<T> From<BlockV0> for Block<T>
Expand All @@ -100,3 +101,141 @@ impl From<BlockV1> for BlockV2 {
}
}
}

impl From<BlockV2> for BlockV3 {
fn from(t: BlockV2) -> Self {
Self {
header: t.header,
transactions: t.transactions.into_iter().map(|t| t.into()).collect(),
ommers: t.ommers,
}
}
}

impl From<BlockV1> for BlockV3 {
fn from(t: BlockV1) -> Self {
Self {
header: t.header,
transactions: t.transactions.into_iter().map(|t| t.into()).collect(),
ommers: t.ommers,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::transaction::{
AuthorizationListItem, EIP7702Transaction, TransactionAction, TransactionV3,
};
use ethereum_types::{H160, H256, U256};

#[test]
fn block_v3_with_eip7702_transaction() {
// Create an EIP-7702 transaction
let eip7702_tx = TransactionV3::EIP7702(EIP7702Transaction {
chain_id: 1,
nonce: U256::from(1),
max_priority_fee_per_gas: U256::from(1_000_000_000),
max_fee_per_gas: U256::from(2_000_000_000),
gas_limit: U256::from(21000),
destination: TransactionAction::Call(H160::zero()),
value: U256::zero(),
data: vec![],
access_list: vec![],
authorization_list: vec![AuthorizationListItem {
chain_id: 1,
address: H160::zero(),
nonce: U256::zero(),
y_parity: false,
r: H256::zero(),
s: H256::zero(),
}],
odd_y_parity: false,
r: H256::zero(),
s: H256::zero(),
});

// Create a block with the EIP-7702 transaction
let partial_header = PartialHeader {
parent_hash: H256::zero(),
beneficiary: H160::zero(),
state_root: H256::zero(),
receipts_root: H256::zero(),
logs_bloom: ethereum_types::Bloom::zero(),
difficulty: U256::zero(),
number: U256::zero(),
gas_limit: U256::from(1_000_000),
gas_used: U256::zero(),
timestamp: 0,
extra_data: vec![],
mix_hash: H256::zero(),
nonce: ethereum_types::H64::zero(),
};

let block = BlockV3::new(partial_header, vec![eip7702_tx.clone()], vec![]);

// Verify the block can be encoded and decoded
let encoded = rlp::encode(&block);
let decoded: BlockV3 = rlp::decode(&encoded).unwrap();

assert_eq!(block, decoded);
assert_eq!(decoded.transactions.len(), 1);

// Verify the transaction is preserved correctly
match &decoded.transactions[0] {
TransactionV3::EIP7702(tx) => {
assert_eq!(tx.chain_id, 1);
assert_eq!(tx.authorization_list.len(), 1);
}
_ => panic!("Expected EIP7702 transaction"),
}
}

#[test]
fn block_v2_to_v3_conversion() {
use crate::transaction::{EIP1559Transaction, TransactionV2};

// Create a BlockV2 with EIP1559 transaction
let eip1559_tx = TransactionV2::EIP1559(EIP1559Transaction {
chain_id: 1,
nonce: U256::from(1),
max_priority_fee_per_gas: U256::from(1_000_000_000),
max_fee_per_gas: U256::from(2_000_000_000),
gas_limit: U256::from(21000),
action: TransactionAction::Call(H160::zero()),
value: U256::zero(),
input: vec![],
access_list: vec![],
odd_y_parity: false,
r: H256::zero(),
s: H256::zero(),
});

let partial_header = PartialHeader {
parent_hash: H256::zero(),
beneficiary: H160::zero(),
state_root: H256::zero(),
receipts_root: H256::zero(),
logs_bloom: ethereum_types::Bloom::zero(),
difficulty: U256::zero(),
number: U256::zero(),
gas_limit: U256::from(1_000_000),
gas_used: U256::zero(),
timestamp: 0,
extra_data: vec![],
mix_hash: H256::zero(),
nonce: ethereum_types::H64::zero(),
};

let block_v2 = BlockV2::new(partial_header, vec![eip1559_tx], vec![]);
let block_v3: BlockV3 = block_v2.into();

// Verify conversion worked
assert_eq!(block_v3.transactions.len(), 1);
match &block_v3.transactions[0] {
TransactionV3::EIP1559(_) => {} // Expected
_ => panic!("Expected EIP1559 transaction in V3"),
}
}
}
19 changes: 19 additions & 0 deletions src/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub type EIP2930ReceiptData = EIP658ReceiptData;

pub type EIP1559ReceiptData = EIP658ReceiptData;

pub type EIP7702ReceiptData = EIP658ReceiptData;

pub type ReceiptV0 = FrontierReceiptData;

impl EnvelopedEncodable for ReceiptV0 {
Expand Down Expand Up @@ -163,6 +165,8 @@ pub enum ReceiptV3 {
EIP2930(EIP2930ReceiptData),
/// EIP-1559 receipt type
EIP1559(EIP1559ReceiptData),
/// EIP-7702 receipt type
EIP7702(EIP7702ReceiptData),
}

impl EnvelopedEncodable for ReceiptV3 {
Expand All @@ -171,6 +175,7 @@ impl EnvelopedEncodable for ReceiptV3 {
Self::Legacy(_) => None,
Self::EIP2930(_) => Some(1),
Self::EIP1559(_) => Some(2),
Self::EIP7702(_) => Some(4),
}
}

Expand All @@ -179,6 +184,7 @@ impl EnvelopedEncodable for ReceiptV3 {
Self::Legacy(r) => rlp::encode(r),
Self::EIP2930(r) => rlp::encode(r),
Self::EIP1559(r) => rlp::encode(r),
Self::EIP7702(r) => rlp::encode(r),
}
}
}
Expand Down Expand Up @@ -208,6 +214,10 @@ impl EnvelopedDecodable for ReceiptV3 {
return Ok(Self::EIP1559(rlp::decode(s)?));
}

if first == 0x04 {
return Ok(Self::EIP7702(rlp::decode(s)?));
}

Err(DecoderError::Custom("invalid receipt type").into())
}
}
Expand All @@ -218,6 +228,7 @@ impl From<ReceiptV3> for EIP658ReceiptData {
ReceiptV3::Legacy(r) => r,
ReceiptV3::EIP2930(r) => r,
ReceiptV3::EIP1559(r) => r,
ReceiptV3::EIP7702(r) => r,
}
}
}
Expand All @@ -241,6 +252,8 @@ pub enum ReceiptAny {
EIP2930(EIP2930ReceiptData),
/// EIP-1559 receipt type
EIP1559(EIP1559ReceiptData),
/// EIP-7702 receipt type
EIP7702(EIP7702ReceiptData),
}

impl EnvelopedEncodable for ReceiptAny {
Expand All @@ -250,6 +263,7 @@ impl EnvelopedEncodable for ReceiptAny {
Self::EIP658(_) => None,
Self::EIP2930(_) => Some(1),
Self::EIP1559(_) => Some(2),
Self::EIP7702(_) => Some(4),
}
}

Expand All @@ -259,6 +273,7 @@ impl EnvelopedEncodable for ReceiptAny {
Self::EIP658(r) => rlp::encode(r),
Self::EIP2930(r) => rlp::encode(r),
Self::EIP1559(r) => rlp::encode(r),
Self::EIP7702(r) => rlp::encode(r),
}
}
}
Expand Down Expand Up @@ -297,6 +312,10 @@ impl EnvelopedDecodable for ReceiptAny {
return Ok(Self::EIP1559(rlp::decode(s)?));
}

if first == 0x04 {
return Ok(Self::EIP7702(rlp::decode(s)?));
}

Err(DecoderError::Custom("invalid receipt type").into())
}
}
Loading
Loading