Skip to content

Commit

Permalink
feat: Cancun support in EDR
Browse files Browse the repository at this point in the history
  • Loading branch information
Wodann committed Oct 5, 2023
1 parent f35dcc6 commit 1d0341d
Show file tree
Hide file tree
Showing 31 changed files with 1,108 additions and 346 deletions.
240 changes: 108 additions & 132 deletions crates/rethnet_eth/src/block.rs

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions crates/rethnet_eth/src/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ pub enum TypedReceiptData {
#[cfg_attr(feature = "serde", serde(with = "crate::serde::u8"))]
status: u8,
},
#[cfg_attr(feature = "serde", serde(rename = "0x3"))]
Eip4844 {
#[cfg_attr(feature = "serde", serde(with = "crate::serde::u8"))]
status: u8,
},
}

impl<LogT> TypedReceipt<LogT> {
Expand All @@ -63,7 +68,8 @@ impl<LogT> TypedReceipt<LogT> {
TypedReceiptData::PreEip658Legacy { .. } => None,
TypedReceiptData::PostEip658Legacy { status }
| TypedReceiptData::Eip2930 { status }
| TypedReceiptData::Eip1559 { status } => Some(*status),
| TypedReceiptData::Eip1559 { status }
| TypedReceiptData::Eip4844 { status } => Some(*status),
}
}

Expand All @@ -82,6 +88,7 @@ impl<LogT> TypedReceipt<LogT> {
| TypedReceiptData::PostEip658Legacy { .. } => 0u64,
TypedReceiptData::Eip2930 { .. } => 1u64,
TypedReceiptData::Eip1559 { .. } => 2u64,
TypedReceiptData::Eip4844 { .. } => 3u64,
}
}
}
Expand Down Expand Up @@ -306,6 +313,7 @@ where
| TypedReceiptData::PostEip658Legacy { .. } => None,
TypedReceiptData::Eip2930 { .. } => Some(1),
TypedReceiptData::Eip1559 { .. } => Some(2),
TypedReceiptData::Eip4844 { .. } => Some(3),
};

if let Some(id) = id {
Expand All @@ -320,7 +328,8 @@ where
}
TypedReceiptData::PostEip658Legacy { status }
| TypedReceiptData::Eip2930 { status }
| TypedReceiptData::Eip1559 { status } => {
| TypedReceiptData::Eip1559 { status }
| TypedReceiptData::Eip4844 { status } => {
if *status == 0 {
s.append_empty_data();
} else {
Expand Down
55 changes: 54 additions & 1 deletion crates/rethnet_eth/src/remote/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
signature::Signature,
transaction::{
EIP1559SignedTransaction, EIP155SignedTransaction, EIP2930SignedTransaction,
LegacySignedTransaction, SignedTransaction, TransactionKind,
Eip4844SignedTransaction, LegacySignedTransaction, SignedTransaction, TransactionKind,
},
withdrawal::Withdrawal,
Address, Bloom, Bytes, B256, U256,
Expand Down Expand Up @@ -82,6 +82,12 @@ pub struct Transaction {
/// max priority fee per gas
#[serde(default)]
pub max_priority_fee_per_gas: Option<U256>,
/// The maximum total fee per gas the sender is willing to pay for blob gas in wei (EIP-4844)
#[serde(default)]
pub max_fee_per_blob_gas: Option<U256>,
/// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs.
#[serde(default)]
pub blob_versioned_hashes: Option<Vec<B256>>,
}

impl Transaction {
Expand All @@ -102,6 +108,9 @@ pub enum TransactionConversionError {
/// Missing access list
#[error("Missing access list")]
MissingAccessList,
/// EIP-4844 transaction is missing blob (versioned) hashes
#[error("Missing blob hashes")]
MissingBlobHashes,
/// Missing chain ID
#[error("Missing chain ID")]
MissingChainId,
Expand All @@ -111,6 +120,12 @@ pub enum TransactionConversionError {
/// Missing max priority fee per gas
#[error("Missing max priority fee per gas")]
MissingMaxPriorityFeePerGas,
/// EIP-4844 transaction is missing the max fee per blob gas
#[error("Missing max fee per blob gas")]
MissingMaxFeePerBlobGas,
/// EIP-4844 transaction is missing the receiver (to) address
#[error("Missing receiver (to) address")]
MissingReceiverAddress,
/// The transaction type is not supported.
#[error("Unsupported type {0}")]
UnsupportedType(u64),
Expand Down Expand Up @@ -203,6 +218,38 @@ impl TryFrom<Transaction> for (SignedTransaction, Address) {
s: value.s,
hash: OnceLock::from(value.hash),
}),
3 => SignedTransaction::Eip4844(Eip4844SignedTransaction {
odd_y_parity: value.odd_y_parity(),
chain_id: value
.chain_id
.ok_or(TransactionConversionError::MissingChainId)?,
nonce: value.nonce,
max_priority_fee_per_gas: value
.max_priority_fee_per_gas
.ok_or(TransactionConversionError::MissingMaxPriorityFeePerGas)?,
max_fee_per_gas: value
.max_fee_per_gas
.ok_or(TransactionConversionError::MissingMaxFeePerGas)?,
max_fee_per_blob_gas: value
.max_fee_per_blob_gas
.ok_or(TransactionConversionError::MissingMaxFeePerBlobGas)?,
gas_limit: value.gas.to(),
to: value
.to
.ok_or(TransactionConversionError::MissingReceiverAddress)?,
value: value.value,
input: value.input,
access_list: value
.access_list
.ok_or(TransactionConversionError::MissingAccessList)?
.into(),
blob_hashes: value
.blob_versioned_hashes
.ok_or(TransactionConversionError::MissingBlobHashes)?,
r: value.r,
s: value.s,
hash: OnceLock::from(value.hash),
}),
r#type => {
return Err(TransactionConversionError::UnsupportedType(r#type));
}
Expand Down Expand Up @@ -275,4 +322,10 @@ pub struct Block<TX> {
pub withdrawals: Option<Vec<Withdrawal>>,
/// withdrawals root
pub withdrawals_root: Option<B256>,
/// The total amount of gas used by the transactions.
#[serde(default, with = "crate::serde::optional_u64")]
pub blob_gas_used: Option<u64>,
/// A running total of blob gas consumed in excess of the target, prior to the block.
#[serde(default, with = "crate::serde::optional_u64")]
pub excess_blob_gas: Option<u64>,
}
6 changes: 5 additions & 1 deletion crates/rethnet_eth/src/transaction/request.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod eip155;
mod eip1559;
mod eip2930;
mod eip4844;
mod legacy;

pub use self::{
eip155::EIP155TransactionRequest, eip1559::EIP1559TransactionRequest,
eip2930::EIP2930TransactionRequest, legacy::LegacyTransactionRequest,
eip2930::EIP2930TransactionRequest, eip4844::Eip4844TransactionRequest,
legacy::LegacyTransactionRequest,
};

/// Container type for various Ethereum transaction requests
Expand All @@ -24,4 +26,6 @@ pub enum TransactionRequest {
EIP2930(EIP2930TransactionRequest),
/// An EIP-1559 transaction request
EIP1559(EIP1559TransactionRequest),
/// An EIP-4844 transaction request
Eip4844(Eip4844TransactionRequest),
}
182 changes: 182 additions & 0 deletions crates/rethnet_eth/src/transaction/request/eip4844.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use std::sync::OnceLock;

use bytes::Bytes;
use revm_primitives::{keccak256, Address, B256, U256};
use secp256k1::SecretKey;

use crate::{
access_list::AccessListItem, signature::Signature, transaction::Eip4844SignedTransaction,
utils::envelop_bytes,
};

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "fastrlp",
derive(open_fastrlp::RlpEncodable, open_fastrlp::RlpDecodable)
)]
pub struct Eip4844TransactionRequest {
pub chain_id: u64,
pub nonce: u64,
pub max_priority_fee_per_gas: U256,
pub max_fee_per_gas: U256,
pub max_fee_per_blob_gas: U256,
pub gas_limit: u64,
pub to: Address,
pub value: U256,
pub input: Bytes,
pub access_list: Vec<AccessListItem>,
pub blob_hashes: Vec<B256>,
}

impl Eip4844TransactionRequest {
/// Computes the hash of the transaction.
pub fn hash(&self) -> B256 {
let encoded = rlp::encode(self);

keccak256(&envelop_bytes(2, &encoded))
}

pub fn sign(self, private_key: &SecretKey) -> Eip4844SignedTransaction {
let hash = self.hash();

let signature = Signature::new(hash, private_key);

Eip4844SignedTransaction {
chain_id: self.chain_id,
nonce: self.nonce,
max_priority_fee_per_gas: self.max_priority_fee_per_gas,
max_fee_per_gas: self.max_fee_per_gas,
max_fee_per_blob_gas: self.max_fee_per_blob_gas,
gas_limit: self.gas_limit,
to: self.to,
value: self.value,
input: self.input,
access_list: self.access_list.into(),
blob_hashes: self.blob_hashes,
odd_y_parity: signature.odd_y_parity(),
r: signature.r,
s: signature.s,
hash: OnceLock::new(),
}
}
}

impl From<&Eip4844SignedTransaction> for Eip4844TransactionRequest {
fn from(t: &Eip4844SignedTransaction) -> Self {
Self {
chain_id: t.chain_id,
nonce: t.nonce,
max_priority_fee_per_gas: t.max_priority_fee_per_gas,
max_fee_per_gas: t.max_fee_per_gas,
max_fee_per_blob_gas: t.max_fee_per_blob_gas,
gas_limit: t.gas_limit,
to: t.to,
value: t.value,
input: t.input.clone(),
access_list: t.access_list.0.clone(),
blob_hashes: t.blob_hashes.clone(),
}
}
}

impl rlp::Encodable for Eip4844TransactionRequest {
fn rlp_append(&self, s: &mut rlp::RlpStream) {
s.begin_list(11);
s.append(&self.chain_id);
s.append(&self.nonce);
s.append(&self.max_priority_fee_per_gas);
s.append(&self.max_fee_per_gas);
s.append(&self.gas_limit);
s.append(&self.to.as_bytes());
s.append(&self.value);
s.append(&self.input.as_ref());
s.append_list(&self.access_list);
s.append(&self.max_fee_per_blob_gas);

let blob_hashes = self
.blob_hashes
.iter()
.map(B256::as_bytes)
.collect::<Vec<_>>();

s.append_list::<&[u8], &[u8]>(blob_hashes.as_slice());
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use revm_primitives::Address;

use super::*;

fn _dummy_request() -> Eip4844TransactionRequest {
let to = Address::from_str("0xc014ba5ec014ba5ec014ba5ec014ba5ec014ba5e").unwrap();
let input = hex::decode("1234").unwrap();
Eip4844TransactionRequest {
chain_id: 1,
nonce: 1,
max_priority_fee_per_gas: U256::from(2),
max_fee_per_gas: U256::from(5),
max_fee_per_blob_gas: U256::from(7),
gas_limit: 3,
to,
value: U256::from(4),
input: Bytes::from(input),
access_list: vec![AccessListItem {
address: Address::zero(),
storage_keys: vec![B256::zero(), B256::from(U256::from(1))],
}],
blob_hashes: vec![B256::zero(), B256::from(U256::from(1))],
}
}

// TODO: add tests
// #[test]
// fn test_eip1559_transaction_request_encoding() {
// // Generated by Hardhat
// // QUESTION: What is considered a valid RLP-encoding? With the prepending type? or without?
// let expected =
// hex::decode("f87b010102050394c014ba5ec014ba5ec014ba5ec014ba5ec014ba5e04821234f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001")
// .unwrap();

// let request = dummy_request();

// let encoded = rlp::encode(&request);
// assert_eq!(expected, encoded.to_vec());
// }

// #[test]
// fn test_eip1559_transaction_request_encoding_empty() {
// // Generated by Hardhat
// let expected = hex::decode("c90180808080808080c0").unwrap();

// let empty = Eip4844TransactionRequest {
// chain_id: 1,
// nonce: 0,
// max_priority_fee_per_gas: U256::ZERO,
// max_fee_per_gas: U256::ZERO,
// gas_limit: 0,
// kind: TransactionKind::Create,
// value: U256::ZERO,
// input: Bytes::new(),
// access_list: vec![],
// };

// let encoded = rlp::encode(&empty);
// assert_eq!(expected, encoded.to_vec());
// }

// #[test]
// fn test_eip1559_transaction_request_hash() {
// // Generated by hardhat
// let expected = B256::from_slice(
// &hex::decode("1d21c520c93f0f8e07c2466361b22a8bb9906cdbf4670e53a701c075bbe69ecf")
// .unwrap(),
// );

// let request = dummy_request();
// assert_eq!(expected, request.hash());
// }
}
Loading

0 comments on commit 1d0341d

Please sign in to comment.