From 417448b50e2e6123eedc51749affaea56d14e983 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sun, 26 Feb 2023 11:55:26 +0200 Subject: [PATCH 1/9] feat: deposit tx --- crates/primitives/Cargo.toml | 1 + crates/primitives/src/lib.rs | 2 + crates/primitives/src/transaction/mod.rs | 103 ++++++++++++++++++ crates/primitives/src/transaction/optimism.rs | 70 ++++++++++++ crates/primitives/src/transaction/tx_type.rs | 12 +- 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 crates/primitives/src/transaction/optimism.rs diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index df03f8b5e3f..bb5c2f47c80 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -85,6 +85,7 @@ pprof = { version = "0.11", features = ["flamegraph", "frame-pointer", "criterio [features] default = [] +optimism = [] arbitrary = [ "revm-primitives/arbitrary", "dep:arbitrary", diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 5a530528120..3007a20847d 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -63,6 +63,8 @@ pub use transaction::{ Transaction, TransactionKind, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy, TxType, }; +#[cfg(feature = "optimism")] +pub use transaction::{TxDeposit, DEPOSIT_TX_TYPE, DEPOSIT_VERSION}; pub use withdrawal::Withdrawal; /// A block hash. diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 4561bf2d695..490e2d139ac 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -14,6 +14,11 @@ mod signature; mod tx_type; mod util; +#[cfg(feature = "optimism")] +mod optimism; +#[cfg(feature = "optimism")] +pub use optimism::{TxDeposit, DEPOSIT_TX_TYPE, DEPOSIT_VERSION}; + /// Legacy transaction. #[main_codec] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] @@ -172,6 +177,9 @@ pub enum Transaction { Eip2930(TxEip2930), /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). Eip1559(TxEip1559), + #[cfg(feature = "optimism")] + /// Deposit transaction. + Deposit(TxDeposit), } impl Transaction { @@ -189,6 +197,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { chain_id, .. }) => *chain_id, Transaction::Eip2930(TxEip2930 { chain_id, .. }) => Some(*chain_id), Transaction::Eip1559(TxEip1559 { chain_id, .. }) => Some(*chain_id), + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => None, } } @@ -198,6 +208,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { chain_id: ref mut c, .. }) => *c = Some(chain_id), Transaction::Eip2930(TxEip2930 { chain_id: ref mut c, .. }) => *c = chain_id, Transaction::Eip1559(TxEip1559 { chain_id: ref mut c, .. }) => *c = chain_id, + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => (), } } @@ -208,6 +220,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { to, .. }) | Transaction::Eip2930(TxEip2930 { to, .. }) | Transaction::Eip1559(TxEip1559 { to, .. }) => to, + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { to, .. }) => to, } } @@ -217,6 +231,8 @@ impl Transaction { Transaction::Legacy { .. } => TxType::Legacy, Transaction::Eip2930 { .. } => TxType::EIP2930, Transaction::Eip1559 { .. } => TxType::EIP1559, + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => TxType::DEPOSIT, } } @@ -226,6 +242,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { value, .. }) => value, Transaction::Eip2930(TxEip2930 { value, .. }) => value, Transaction::Eip1559(TxEip1559 { value, .. }) => value, + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { value, .. }) => value, } } @@ -235,6 +253,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { nonce, .. }) => *nonce, Transaction::Eip2930(TxEip2930 { nonce, .. }) => *nonce, Transaction::Eip1559(TxEip1559 { nonce, .. }) => *nonce, + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => todo!(), // TODO: } } @@ -244,6 +264,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { gas_limit, .. }) | Transaction::Eip2930(TxEip2930 { gas_limit, .. }) | Transaction::Eip1559(TxEip1559 { gas_limit, .. }) => *gas_limit, + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { gas_limit, .. }) => *gas_limit, } } @@ -253,6 +275,10 @@ impl Transaction { Transaction::Legacy(TxLegacy { gas_price, .. }) | Transaction::Eip2930(TxEip2930 { gas_price, .. }) => *gas_price, Transaction::Eip1559(TxEip1559 { max_fee_per_gas, .. }) => *max_fee_per_gas, + #[cfg(feature = "optimism")] + // Deposit transactions buy their L2 gas on L1 and, as such, the L2 gas is not + // refundable. + Transaction::Deposit(_) => 0, } } @@ -265,6 +291,8 @@ impl Transaction { Transaction::Eip1559(TxEip1559 { max_priority_fee_per_gas, .. }) => { Some(*max_priority_fee_per_gas) } + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => None, } } @@ -274,6 +302,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { input, .. }) => input, Transaction::Eip2930(TxEip2930 { input, .. }) => input, Transaction::Eip1559(TxEip1559 { input, .. }) => input, + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { input, .. }) => input, } } @@ -370,6 +400,8 @@ impl Transaction { len += access_list.length(); len } + #[cfg(feature = "optimism")] + Transaction::Deposit(deposit) => deposit.fields_len(), } } @@ -432,6 +464,8 @@ impl Transaction { input.0.encode(out); access_list.encode(out); } + #[cfg(feature = "optimism")] + Transaction::Deposit(deposit) => deposit.encode_fields(out), } } } @@ -453,6 +487,13 @@ impl Encodable for Transaction { self.encode_fields(out); self.encode_eip155_fields(out); } + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => { + out.put_u8(self.tx_type() as u8); + out.put_u8(DEPOSIT_VERSION); + Header { list: true, payload_length: self.fields_len() }.encode(out); + self.encode_fields(out); + } _ => { out.put_u8(self.tx_type() as u8); Header { list: true, payload_length: self.fields_len() }.encode(out); @@ -468,6 +509,12 @@ impl Encodable for Transaction { // 'header length' + 'payload length' length_of_length(payload_length) + payload_length } + #[cfg(feature = "optimism")] + Transaction::Deposit { .. } => { + let payload_length = self.fields_len(); + // 'tx type byte length' + 'version byte' + 'header length' + 'payload length' + 1 + 1 + length_of_length(payload_length) + payload_length + } _ => { let payload_length = self.fields_len(); // 'transaction type byte length' + 'header length' + 'payload length' @@ -551,6 +598,10 @@ impl TransactionSigned { /// /// Returns `None` if the transaction's signature is invalid. pub fn recover_signer(&self) -> Option
{ + #[cfg(feature = "optimism")] + if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { + return Some(from.clone()) + } let signature_hash = self.signature_hash(); self.signature.recover_signer(signature_hash) } @@ -601,6 +652,23 @@ impl TransactionSigned { self.transaction.encode_fields(out); self.signature.encode_with_eip155_chain_id(out, chain_id); } + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => { + let payload_length = self.transaction.fields_len() + self.signature.payload_len(); + if with_header { + Header { + list: false, + payload_length: 1 + 1 + length_of_length(payload_length) + payload_length, + } + .encode(out); + } + out.put_u8(self.transaction.tx_type() as u8); + out.put_u8(DEPOSIT_VERSION); + let header = Header { list: true, payload_length }; + header.encode(out); + self.transaction.encode_fields(out); + self.signature.encode(out); + } _ => { let payload_length = self.transaction.fields_len() + self.signature.payload_len(); if with_header { @@ -629,6 +697,13 @@ impl TransactionSigned { // 'header length' + 'payload length' length_of_length(payload_length) + payload_length } + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => { + let payload_length = self.transaction.fields_len() + self.signature.payload_len(); + // 'tx type byte length' + 'version byte' + 'header length' + 'payload length' + let len = 1 + 1 + length_of_length(payload_length) + payload_length; + length_of_length(len) + len + } _ => { let payload_length = self.transaction.fields_len() + self.signature.payload_len(); // 'transaction type byte length' + 'header length' + 'payload length' @@ -694,6 +769,16 @@ impl TransactionSigned { let tx_type = *data.first().ok_or(DecodeError::InputTooShort)?; data.advance(1); + + #[cfg(feature = "optimism")] + if tx_type == DEPOSIT_TX_TYPE { + let version = *data.first().ok_or(DecodeError::InputTooShort)?; + if version != DEPOSIT_VERSION { + return Err(DecodeError::Custom("Deposit version mismatch")) + } + data.advance(1); + } + // decode the list header for the rest of the transaction let header = Header::decode(data)?; if !header.list { @@ -702,6 +787,8 @@ impl TransactionSigned { // length of tx encoding = tx type byte (size = 1) + length of header + payload length let tx_length = 1 + header.length() + header.payload_length; + #[cfg(feature = "optimism")] + let tx_length = if tx_type == DEPOSIT_TX_TYPE { tx_length + 1 } else { tx_length }; // decode common fields let transaction = match tx_type { @@ -726,6 +813,22 @@ impl TransactionSigned { input: Bytes(Decodable::decode(data)?), access_list: Decodable::decode(data)?, }), + #[cfg(feature = "optimism")] + DEPOSIT_TX_TYPE => Transaction::Deposit(TxDeposit { + source_hash: Decodable::decode(data)?, + from: Decodable::decode(data)?, + to: Decodable::decode(data)?, + mint: if *data.first().ok_or(DecodeError::InputTooShort)? == EMPTY_STRING_CODE { + data.advance(1); + None + } else { + Some(Decodable::decode(data)?) + }, + value: Decodable::decode(data)?, + input: Decodable::decode(data)?, + gas_limit: Decodable::decode(data)?, + is_system_transaction: Decodable::decode(data)?, + }), _ => return Err(DecodeError::Custom("unsupported typed transaction type")), }; diff --git a/crates/primitives/src/transaction/optimism.rs b/crates/primitives/src/transaction/optimism.rs new file mode 100644 index 00000000000..1b48f43fd23 --- /dev/null +++ b/crates/primitives/src/transaction/optimism.rs @@ -0,0 +1,70 @@ +use crate::{Address, Bytes, TransactionKind, H256}; +use reth_codecs::{main_codec, Compact}; +use reth_rlp::{Encodable, EMPTY_STRING_CODE}; + +/// EIP-2718 transaction type selector. +pub const DEPOSIT_TX_TYPE: u8 = 126; + +/// A versioned byte sequence to enable the protocol to upgrade the deposit transaction type without +/// changing the transaction type selector. +pub const DEPOSIT_VERSION: u8 = 0; + +/// Deposited transactions, also known as deposits are transactions which are initiated on L1, and +/// executed on L2. This document outlines a new transaction type for deposits. It also describes +/// how deposits are initiated on L1, along with the authorization and validation conditions on L2. +#[main_codec] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct TxDeposit { + /// Hash that uniquely identifies the source of the deposit. + pub source_hash: H256, + /// The address of the sender account. + pub from: Address, + /// The address of the recipient account, or the null (zero-length) address if the deposited + /// transaction is a contract creation. + pub to: TransactionKind, + /// The ETH value to mint on L2. + pub mint: Option, + /// The ETH value to send to the recipient account. + pub value: u128, + /// The gas limit for the L2 transaction. + pub gas_limit: u64, + /// Field indicating if this transaction is exempt from the L2 gas limit. + pub is_system_transaction: bool, + /// Input has two uses depending if transaction is Create or Call (if `to` field is None or + /// Some). + pub input: Bytes, +} + +impl TxDeposit { + /// Outputs the length of the transaction's fields, without a RLP header or length of the + /// eip155 fields. + pub(crate) fn fields_len(&self) -> usize { + let mut len = 0; + len += self.source_hash.length(); + len += self.from.length(); + len += self.to.length(); + len += self.mint.map(|mint| mint.length()).unwrap_or(1); + len += self.value.length(); + len += self.input.0.length(); + len += self.gas_limit.length(); + len += self.is_system_transaction.length(); + len + } + + /// Encodes only the transaction's fields into the desired buffer, without a RLP header. + /// https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#the-deposited-transaction-type + pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { + self.source_hash.encode(out); + self.from.encode(out); + self.to.encode(out); + if let Some(mint) = self.mint { + mint.encode(out); + } else { + out.put_u8(EMPTY_STRING_CODE); + } + self.value.encode(out); + self.input.encode(out); + self.gas_limit.encode(out); + self.is_system_transaction.encode(out); + } +} diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index c2d86fe6879..ca7f2ebd6bd 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -12,6 +12,9 @@ pub enum TxType { EIP2930 = 1_isize, /// Transaction with Priority fee EIP1559 = 2_isize, + #[cfg(feature = "optimism")] + /// OP Deposit transaction. + DEPOSIT = 126_isize, } impl From for u8 { @@ -20,6 +23,8 @@ impl From for u8 { TxType::Legacy => 0, TxType::EIP2930 => 1, TxType::EIP1559 => 2, + #[cfg(feature = "optimism")] + TxType::DEPOSIT => 126, } } } @@ -30,6 +35,8 @@ impl Compact for TxType { TxType::Legacy => 0, TxType::EIP2930 => 1, TxType::EIP1559 => 2, + #[cfg(feature = "optimism")] + TxType::DEPOSIT => 126, } } @@ -38,7 +45,10 @@ impl Compact for TxType { match identifier { 0 => TxType::Legacy, 1 => TxType::EIP2930, - _ => TxType::EIP1559, + 2 => TxType::EIP1559, + #[cfg(feature = "optimism")] + 126 => TxType::DEPOSIT, + _ => panic!("unknown transaction type {identifier}"), }, buf, ) From 5fb2582f2d0edbba5df02c746f0d7ca884e48104 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sun, 26 Feb 2023 14:13:36 +0200 Subject: [PATCH 2/9] chainspec and forks --- crates/primitives/src/chain/spec.rs | 44 +++++++++++++++++++++++++++++ crates/primitives/src/hardfork.rs | 22 +++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index 0fdaa93ec14..b3b5be9889c 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -40,6 +40,8 @@ pub static MAINNET: Lazy = Lazy::new(|| ChainSpec { }, ), ]), + #[cfg(feature = "optimism")] + optimism: None, }); /// The Goerli spec @@ -60,6 +62,8 @@ pub static GOERLI: Lazy = Lazy::new(|| ChainSpec { ForkCondition::TTD { fork_block: None, total_difficulty: U256::from(10_790_000) }, ), ]), + #[cfg(feature = "optimism")] + optimism: None, }); /// The Sepolia spec @@ -92,6 +96,8 @@ pub static SEPOLIA: Lazy = Lazy::new(|| ChainSpec { ), (Hardfork::Shanghai, ForkCondition::Timestamp(1677557088)), ]), + #[cfg(feature = "optimism")] + optimism: None, }); /// An Ethereum chain specification. @@ -118,6 +124,20 @@ pub struct ChainSpec { /// The active hard forks and their activation conditions pub hardforks: BTreeMap, + + #[cfg(feature = "optimism")] + /// Optimism configuration + pub optimism: Option, +} + +#[cfg(feature = "optimism")] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Optimism configuration. +pub struct OptimismConfig { + /// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) + pub eip_1559_elasticity: u64, + /// Base fee max change denominator as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) + pub eip_1559_denominator: u64, } impl ChainSpec { @@ -293,6 +313,8 @@ impl From for ChainSpec { genesis: genesis_block, genesis_hash: None, hardforks, + #[cfg(feature = "optimism")] + optimism: None, } } } @@ -334,6 +356,8 @@ pub struct ChainSpecBuilder { chain: Option, genesis: Option, hardforks: BTreeMap, + #[cfg(feature = "optimism")] + optimism: Option, } impl ChainSpecBuilder { @@ -343,6 +367,8 @@ impl ChainSpecBuilder { chain: Some(MAINNET.chain), genesis: Some(MAINNET.genesis.clone()), hardforks: MAINNET.hardforks.clone(), + #[cfg(feature = "optimism")] + optimism: None, } } @@ -443,6 +469,20 @@ impl ChainSpecBuilder { self } + #[cfg(feature = "optimism")] + /// Enable Bedrock at genesis + pub fn bedrock_activated(mut self) -> Self { + self.hardforks.insert(Hardfork::Bedrock, ForkCondition::Block(0)); + self + } + + #[cfg(feature = "optimism")] + /// Enable Bedrock at genesis + pub fn regolith_activated(mut self) -> Self { + self.hardforks.insert(Hardfork::Regolith, ForkCondition::Timestamp(0)); + self + } + /// Build the resulting [`ChainSpec`]. /// /// # Panics @@ -455,6 +495,8 @@ impl ChainSpecBuilder { genesis: self.genesis.expect("The genesis is required"), genesis_hash: None, hardforks: self.hardforks, + #[cfg(feature = "optimism")] + optimism: self.optimism, } } } @@ -465,6 +507,8 @@ impl From<&ChainSpec> for ChainSpecBuilder { chain: Some(value.chain), genesis: Some(value.genesis.clone()), hardforks: value.hardforks.clone(), + #[cfg(feature = "optimism")] + optimism: value.optimism.clone(), } } } diff --git a/crates/primitives/src/hardfork.rs b/crates/primitives/src/hardfork.rs index 0f5be37c664..47adfd39352 100644 --- a/crates/primitives/src/hardfork.rs +++ b/crates/primitives/src/hardfork.rs @@ -39,6 +39,12 @@ pub enum Hardfork { Paris, /// Shanghai. Shanghai, + #[cfg(feature = "optimism")] + /// Bedrock. + Bedrock, + #[cfg(feature = "optimism")] + /// Regolith + Regolith, } impl Hardfork { @@ -82,6 +88,10 @@ impl FromStr for Hardfork { "grayglacier" => Hardfork::GrayGlacier, "paris" => Hardfork::Paris, "shanghai" => Hardfork::Shanghai, + #[cfg(feature = "optimism")] + "bedrock" => Hardfork::Bedrock, + #[cfg(feature = "optimism")] + "regolith" => Hardfork::Regolith, _ => return Err(format!("Unknown hardfork: {s}")), }; Ok(hardfork) @@ -146,6 +156,18 @@ mod tests { assert_eq!(hardforks, expected_hardforks); } + #[test] + #[cfg(feature = "optimism")] + fn check_op_hardfork_from_str() { + let hardfork_str = ["beDrOck", "rEgOlITH"]; + let expected_hardforks = [Hardfork::Bedrock, Hardfork::Regolith]; + + let hardforks: Vec = + hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect(); + + assert_eq!(hardforks, expected_hardforks); + } + #[test] fn check_nonexistent_hardfork_from_str() { assert!(Hardfork::from_str("not a hardfork").is_err()); From 05d6b548835e80a2a76e434b071202609e154f60 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sun, 26 Feb 2023 14:41:49 +0200 Subject: [PATCH 3/9] feat: payload attributes op fields --- crates/rpc/rpc-types/Cargo.toml | 3 +++ crates/rpc/rpc-types/src/eth/engine.rs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/crates/rpc/rpc-types/Cargo.toml b/crates/rpc/rpc-types/Cargo.toml index d3d5a9d1c18..684cb06fd10 100644 --- a/crates/rpc/rpc-types/Cargo.toml +++ b/crates/rpc/rpc-types/Cargo.toml @@ -28,3 +28,6 @@ lru = "0.9" [dev-dependencies] reth-interfaces = { path = "../../interfaces", features = ["test-utils"] } + +[features] +optimism = ["reth-primitives/optimism"] diff --git a/crates/rpc/rpc-types/src/eth/engine.rs b/crates/rpc/rpc-types/src/eth/engine.rs index 7ef76d02b65..22c736dc1ab 100644 --- a/crates/rpc/rpc-types/src/eth/engine.rs +++ b/crates/rpc/rpc-types/src/eth/engine.rs @@ -125,6 +125,22 @@ pub struct PayloadAttributes { /// See #[serde(default, skip_serializing_if = "Option::is_none")] pub withdrawals: Option>, + + #[cfg(feature = "optimism")] + /// Transactions is a field for rollups: the transactions list is forced into the block + #[serde(default, skip_serializing_if = "Option::is_none")] + pub transactions: Option>, + + #[cfg(feature = "optimism")] + /// If true, the no transactions are taken out of the tx-pool, only transactions from the above + /// Transactions list will be included. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub no_tx_pool: Option, + + #[cfg(feature = "optimism")] + /// If set, this sets the exact gas limit the block produced with. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub gas_limit: Option, } /// This structure contains the result of processing a payload From 94f838d15a3c05efa10bb32caf2f64fc626df8ff Mon Sep 17 00:00:00 2001 From: clabby Date: Sun, 26 Feb 2023 20:36:42 -0500 Subject: [PATCH 4/9] Small changes to the deposit tx primitive --- crates/primitives/src/transaction/mod.rs | 49 ++++++++++++++++++- crates/primitives/src/transaction/optimism.rs | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 490e2d139ac..c47164cf8c7 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -6,6 +6,7 @@ use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; use reth_rlp::{ length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE, }; +use revm_primitives::U256; pub use signature::Signature; pub use tx_type::TxType; @@ -254,7 +255,8 @@ impl Transaction { Transaction::Eip2930(TxEip2930 { nonce, .. }) => *nonce, Transaction::Eip1559(TxEip1559 { nonce, .. }) => *nonce, #[cfg(feature = "optimism")] - Transaction::Deposit(_) => todo!(), // TODO: + // Deposit transactions don't have a nonce, so they default to zero. + Transaction::Deposit(_) => 0, } } @@ -307,6 +309,36 @@ impl Transaction { } } + #[cfg(feature = "optimism")] + /// Returns the source hash of the transaction, which uniquely identifies its source. + /// If the transaction is not a deposit transaction, this will always return `H256::zero()`. + pub fn source_hash(&self) -> H256 { + match self { + Transaction::Deposit(TxDeposit { source_hash, .. }) => *source_hash, + _ => H256::zero(), + } + } + + #[cfg(feature = "optimism")] + /// Returns the amount of ETH locked up on L1 that will be minted on L2. If the transaction + /// is not a deposit transaction, this will always return `None`. + pub fn mint(&self) -> Option { + match self { + Transaction::Deposit(TxDeposit { mint, .. }) => *mint, + _ => None, + } + } + + #[cfg(feature = "optimism")] + /// Returns whether or not the transaction is a system transaction. If the transaction + /// is not a deposit transaction, this will always return `false`. + pub fn is_system_transaction(&self) -> bool { + match self { + Transaction::Deposit(TxDeposit { is_system_transaction, .. }) => *is_system_transaction, + _ => false, + } + } + /// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy /// transactions. pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) { @@ -667,7 +699,16 @@ impl TransactionSigned { let header = Header { list: true, payload_length }; header.encode(out); self.transaction.encode_fields(out); - self.signature.encode(out); + // Deposit transactions do not have a signature. If the signature's values are not + // zero, then the transaction is invalid. + if self.signature().v(self.chain_id()) != 0 || + self.signature().r != U256::ZERO || + self.signature().s != U256::ZERO + { + // TODO: Ensure that this transaction may never have a non-zero signature + // higher up - we shouldn't be panicking here. + panic!("Deposit transactions must have a zero signature"); + } } _ => { let payload_length = self.transaction.fields_len() + self.signature.payload_len(); @@ -771,6 +812,8 @@ impl TransactionSigned { data.advance(1); #[cfg(feature = "optimism")] + // If the transaction is a deposit, we need to first ensure that the version + // byte is correct. if tx_type == DEPOSIT_TX_TYPE { let version = *data.first().ok_or(DecodeError::InputTooShort)?; if version != DEPOSIT_VERSION { @@ -788,6 +831,8 @@ impl TransactionSigned { // length of tx encoding = tx type byte (size = 1) + length of header + payload length let tx_length = 1 + header.length() + header.payload_length; #[cfg(feature = "optimism")] + // If the transaction is a deposit, we need to add one to the length to account for the + // version byte. let tx_length = if tx_type == DEPOSIT_TX_TYPE { tx_length + 1 } else { tx_length }; // decode common fields diff --git a/crates/primitives/src/transaction/optimism.rs b/crates/primitives/src/transaction/optimism.rs index 1b48f43fd23..31c272555fc 100644 --- a/crates/primitives/src/transaction/optimism.rs +++ b/crates/primitives/src/transaction/optimism.rs @@ -43,7 +43,7 @@ impl TxDeposit { len += self.source_hash.length(); len += self.from.length(); len += self.to.length(); - len += self.mint.map(|mint| mint.length()).unwrap_or(1); + len += self.mint.map_or(1, |mint| mint.length()); len += self.value.length(); len += self.input.0.length(); len += self.gas_limit.length(); From da34f331cba7c71c324eee76a8504924655accc6 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Sun, 26 Feb 2023 18:39:58 -0700 Subject: [PATCH 5/9] small fixes --- crates/primitives/src/transaction/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 490e2d139ac..724130fbb52 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -408,6 +408,17 @@ impl Transaction { /// Encodes only the transaction's fields into the desired buffer, without a RLP header. pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { match self { + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { to, mint, value, gas_limit, input, .. }) => { + tx_env.gas_limit = *gas_limit; + tx_env.gas_price = U256::from(*mint); + tx_env.gas_priority_fee = None; + tx_env.transact_to = TransactTo::Call(*to); + tx_env.value = U256::from(*value); + tx_env.data = input.0.clone(); + tx_env.chain_id = None; + tx_env.nonce = None; + } Transaction::Legacy(TxLegacy { chain_id: _, nonce, From ab37bb7d28efe5de8eb109f541a92bc71a995992 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Sun, 26 Feb 2023 19:39:42 -0700 Subject: [PATCH 6/9] more small fixes --- crates/primitives/src/transaction/mod.rs | 14 ++------ crates/revm/revm-primitives/Cargo.toml | 5 +-- crates/revm/revm-primitives/src/env.rs | 14 ++++++++ crates/transaction-pool/Cargo.toml | 1 + .../transaction-pool/src/test_utils/mock.rs | 34 +++++++++++++++++++ crates/transaction-pool/src/traits.rs | 2 ++ 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 798bab96af5..d154e635c9b 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -6,6 +6,7 @@ use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; use reth_rlp::{ length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE, }; +#[cfg(feature = "optimism")] use revm_primitives::U256; pub use signature::Signature; pub use tx_type::TxType; @@ -440,17 +441,6 @@ impl Transaction { /// Encodes only the transaction's fields into the desired buffer, without a RLP header. pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { match self { - #[cfg(feature = "optimism")] - Transaction::Deposit(TxDeposit { to, mint, value, gas_limit, input, .. }) => { - tx_env.gas_limit = *gas_limit; - tx_env.gas_price = U256::from(*mint); - tx_env.gas_priority_fee = None; - tx_env.transact_to = TransactTo::Call(*to); - tx_env.value = U256::from(*value); - tx_env.data = input.0.clone(); - tx_env.chain_id = None; - tx_env.nonce = None; - } Transaction::Legacy(TxLegacy { chain_id: _, nonce, @@ -643,7 +633,7 @@ impl TransactionSigned { pub fn recover_signer(&self) -> Option
{ #[cfg(feature = "optimism")] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { - return Some(from.clone()) + return Some(from) } let signature_hash = self.signature_hash(); self.signature.recover_signer(signature_hash) diff --git a/crates/revm/revm-primitives/Cargo.toml b/crates/revm/revm-primitives/Cargo.toml index 57ccc160e70..87ba3ea0bfe 100644 --- a/crates/revm/revm-primitives/Cargo.toml +++ b/crates/revm/revm-primitives/Cargo.toml @@ -7,7 +7,8 @@ repository = "https://github.com/paradigmxyz/reth" description = "core reth specific revm utilities" [dependencies] -# reth reth-primitives = { path = "../../primitives" } +revm = { version = "3.0.0" } -revm = { version = "3.0.0" } \ No newline at end of file +[features] +optimism = [] diff --git a/crates/revm/revm-primitives/src/env.rs b/crates/revm/revm-primitives/src/env.rs index c6bbf1802f4..6c151abeff1 100644 --- a/crates/revm/revm-primitives/src/env.rs +++ b/crates/revm/revm-primitives/src/env.rs @@ -5,6 +5,9 @@ use reth_primitives::{ }; use revm::primitives::{AnalysisKind, BlockEnv, CfgEnv, Env, SpecId, TransactTo, TxEnv}; +#[cfg(feature = "optimism")] +use reth_primitives::TxDeposit; + /// Convenience function to call both [fill_cfg_env] and [fill_block_env] pub fn fill_cfg_and_block_env( env: &mut Env, @@ -60,6 +63,17 @@ pub fn fill_block_env(block_env: &mut BlockEnv, header: &Header, after_merge: bo pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { tx_env.caller = sender; match transaction.as_ref() { + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { to, mint, value, gas_limit, input, .. }) => { + tx_env.gas_limit = *gas_limit; + tx_env.gas_price = U256::from(*mint); + tx_env.gas_priority_fee = None; + tx_env.transact_to = TransactTo::Call(*to); + tx_env.value = U256::from(*value); + tx_env.data = input.0.clone(); + tx_env.chain_id = None; + tx_env.nonce = None; + } Transaction::Legacy(TxLegacy { nonce, chain_id, diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index 34a09589b3b..846686b3c2d 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -57,3 +57,4 @@ rand = "0.8" default = ["serde"] serde = ["dep:serde"] test-utils = ["rand", "paste", "serde"] +optimism = [] \ No newline at end of file diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index da03552b807..8545f53bf8f 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -21,6 +21,9 @@ pub(crate) type MockTxPool = TxPool; pub type MockValidTx = ValidPoolTransaction; +#[cfg(feature = "optimism")] +use reth_primitives::TxDeposit; + /// Create an empty `TxPool` pub(crate) fn mock_tx_pool() -> MockTxPool { MockTxPool::new(Arc::new(Default::default()), Default::default()) @@ -98,6 +101,17 @@ pub enum MockTransaction { to: TransactionKind, value: U256, }, + #[cfg(feature = "optimism")] + DepositTx { + source_hash: H256, + from: Address, + to: TransactionKind, + mint: Option, + value: u128, + gas_limit: u64, + is_system_transaction: bool, + input: Bytes, + }, } // === impl MockTransaction === @@ -364,6 +378,26 @@ impl FromRecoveredTransaction for MockTransaction { let transaction = tx.into_signed(); let hash = transaction.hash; match transaction.transaction { + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { + source_hash, + from, + to, + mint, + value, + gas_limit, + is_system_transaction, + input, + }) => MockTransaction::DepositTx { + source_hash, + from, + to, + mint, + value, + gas_limit, + is_system_transaction, + input, + }, Transaction::Legacy(TxLegacy { chain_id, nonce, diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 94a4d358094..7b36e462833 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -353,6 +353,8 @@ impl PoolTransaction for PooledTransaction { /// This will return `None` for non-EIP1559 transactions fn max_fee_per_gas(&self) -> Option { match &self.transaction.transaction { + #[cfg(feature = "optimism")] + Transaction::Optimism(_) => None, Transaction::Legacy(_) => None, Transaction::Eip2930(_) => None, Transaction::Eip1559(tx) => Some(tx.max_fee_per_gas), From 3ff20144785a5c20230e536b958e10e2307aac51 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Sun, 26 Feb 2023 22:26:58 -0700 Subject: [PATCH 7/9] compiles --- crates/consensus/Cargo.toml | 3 ++ crates/consensus/src/validation.rs | 8 ++++ crates/primitives/src/hardfork.rs | 4 ++ crates/revm/revm-primitives/src/env.rs | 11 ++++- crates/rpc/rpc-types/src/eth/engine.rs | 2 +- .../rpc/rpc-types/src/eth/transaction/mod.rs | 4 ++ .../transaction-pool/src/test_utils/mock.rs | 48 ++++++++++++++++--- crates/transaction-pool/src/traits.rs | 12 ++++- 8 files changed, 82 insertions(+), 10 deletions(-) diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index 1cd67f69d92..bd742d0bed0 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -19,3 +19,6 @@ tokio = { version = "1", features = ["sync"] } reth-interfaces = { path = "../interfaces", features = ["test-utils"] } reth-provider = { path = "../storage/provider", features = ["test-utils"] } assert_matches = "1.5.0" + +[features] +optimism = [] \ No newline at end of file diff --git a/crates/consensus/src/validation.rs b/crates/consensus/src/validation.rs index b786fd618be..46363405bac 100644 --- a/crates/consensus/src/validation.rs +++ b/crates/consensus/src/validation.rs @@ -12,6 +12,9 @@ use std::{ use reth_primitives::constants; +#[cfg(feature = "optimism")] +use reth_primitives::TxDeposit; + /// Validate header standalone pub fn validate_header_standalone( header: &SealedHeader, @@ -69,6 +72,11 @@ pub fn validate_transaction_regarding_header( base_fee: Option, ) -> Result<(), Error> { let chain_id = match transaction { + #[cfg(feature = "optimism")] + Transaction::Deposit(TxDeposit { .. }) => { + // TODO: get the chain id + None + } Transaction::Legacy(TxLegacy { chain_id, .. }) => { // EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155 if chain_spec.fork(Hardfork::SpuriousDragon).active_at_block(at_block_number) && diff --git a/crates/primitives/src/hardfork.rs b/crates/primitives/src/hardfork.rs index 47adfd39352..cc5d384faeb 100644 --- a/crates/primitives/src/hardfork.rs +++ b/crates/primitives/src/hardfork.rs @@ -180,6 +180,8 @@ mod tests { genesis: Genesis::default(), genesis_hash: None, hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]), + #[cfg(feature = "optimism")] + optimism: None, }; assert_eq!(Hardfork::Frontier.fork_id(&spec), None); @@ -192,6 +194,8 @@ mod tests { genesis: Genesis::default(), genesis_hash: None, hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]), + #[cfg(feature = "optimism")] + optimism: None, }; assert_eq!(Hardfork::Shanghai.fork_filter(&spec), None); diff --git a/crates/revm/revm-primitives/src/env.rs b/crates/revm/revm-primitives/src/env.rs index 6c151abeff1..74445f70481 100644 --- a/crates/revm/revm-primitives/src/env.rs +++ b/crates/revm/revm-primitives/src/env.rs @@ -66,9 +66,16 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: #[cfg(feature = "optimism")] Transaction::Deposit(TxDeposit { to, mint, value, gas_limit, input, .. }) => { tx_env.gas_limit = *gas_limit; - tx_env.gas_price = U256::from(*mint); + if let Some(m) = mint { + tx_env.gas_price = U256::from(*m); + } else { + tx_env.gas_price = U256::ZERO; + } tx_env.gas_priority_fee = None; - tx_env.transact_to = TransactTo::Call(*to); + match to { + TransactionKind::Call(to) => tx_env.transact_to = TransactTo::Call(*to), + TransactionKind::Create => tx_env.transact_to = TransactTo::create(), + } tx_env.value = U256::from(*value); tx_env.data = input.0.clone(); tx_env.chain_id = None; diff --git a/crates/rpc/rpc-types/src/eth/engine.rs b/crates/rpc/rpc-types/src/eth/engine.rs index 22c736dc1ab..e8be77f3adc 100644 --- a/crates/rpc/rpc-types/src/eth/engine.rs +++ b/crates/rpc/rpc-types/src/eth/engine.rs @@ -140,7 +140,7 @@ pub struct PayloadAttributes { #[cfg(feature = "optimism")] /// If set, this sets the exact gas limit the block produced with. #[serde(default, skip_serializing_if = "Option::is_none")] - pub gas_limit: Option, + pub gas_limit: Option, } /// This structure contains the result of processing a payload diff --git a/crates/rpc/rpc-types/src/eth/transaction/mod.rs b/crates/rpc/rpc-types/src/eth/transaction/mod.rs index 940085948ab..035f00890bb 100644 --- a/crates/rpc/rpc-types/src/eth/transaction/mod.rs +++ b/crates/rpc/rpc-types/src/eth/transaction/mod.rs @@ -102,10 +102,14 @@ impl Transaction { TxType::Legacy => (Some(U128::from(signed_tx.max_fee_per_gas())), None), TxType::EIP2930 => (None, Some(U128::from(signed_tx.max_fee_per_gas()))), TxType::EIP1559 => (None, Some(U128::from(signed_tx.max_fee_per_gas()))), + #[cfg(feature = "optimism")] + TxType::DEPOSIT => (None, None), }; let chain_id = signed_tx.chain_id().map(U64::from); let access_list = match &signed_tx.transaction { + #[cfg(feature = "optimism")] + PrimitiveTransaction::Deposit(_) => None, PrimitiveTransaction::Legacy(_) => None, PrimitiveTransaction::Eip2930(tx) => Some( tx.access_list diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index 8545f53bf8f..ebdf9841770 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -21,9 +21,15 @@ pub(crate) type MockTxPool = TxPool; pub type MockValidTx = ValidPoolTransaction; +#[cfg(feature = "optimism")] +use reth_primitives::DEPOSIT_TX_TYPE; + #[cfg(feature = "optimism")] use reth_primitives::TxDeposit; +#[cfg(feature = "optimism")] +use reth_primitives::Bytes; + /// Create an empty `TxPool` pub(crate) fn mock_tx_pool() -> MockTxPool { MockTxPool::new(Arc::new(Default::default()), Default::default()) @@ -34,6 +40,10 @@ macro_rules! set_value { ($this:ident => $field:ident) => { let new_value = $field; match $this { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { ref mut $field, .. } => { + *$field = new_value; + } MockTransaction::Legacy { ref mut $field, .. } => { *$field = new_value; } @@ -48,6 +58,8 @@ macro_rules! set_value { macro_rules! get_value { ($this:ident => $field:ident) => { match $this { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { $field, .. } => $field, MockTransaction::Legacy { $field, .. } => $field, MockTransaction::Eip1559 { $field, .. } => $field, } @@ -103,14 +115,15 @@ pub enum MockTransaction { }, #[cfg(feature = "optimism")] DepositTx { - source_hash: H256, - from: Address, + hash: H256, + sender: Address, + nonce: u64, to: TransactionKind, mint: Option, - value: u128, gas_limit: u64, is_system_transaction: bool, input: Bytes, + value: U256, }, } @@ -198,6 +211,8 @@ impl MockTransaction { pub fn set_gas_price(&mut self, val: u128) -> &mut Self { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => {} MockTransaction::Legacy { gas_price, .. } => { *gas_price = val; } @@ -211,6 +226,8 @@ impl MockTransaction { pub fn with_gas_price(mut self, val: u128) -> Self { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => {} MockTransaction::Legacy { ref mut gas_price, .. } => { *gas_price = val; } @@ -228,6 +245,8 @@ impl MockTransaction { pub fn get_gas_price(&self) -> u128 { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => 0, MockTransaction::Legacy { gas_price, .. } => *gas_price, MockTransaction::Eip1559 { max_fee_per_gas, .. } => *max_fee_per_gas, } @@ -295,6 +314,8 @@ impl MockTransaction { impl PoolTransaction for MockTransaction { fn hash(&self) -> &TxHash { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { hash, .. } => hash, MockTransaction::Legacy { hash, .. } => hash, MockTransaction::Eip1559 { hash, .. } => hash, } @@ -302,6 +323,8 @@ impl PoolTransaction for MockTransaction { fn sender(&self) -> Address { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { sender, .. } => *sender, MockTransaction::Legacy { sender, .. } => *sender, MockTransaction::Eip1559 { sender, .. } => *sender, } @@ -309,6 +332,8 @@ impl PoolTransaction for MockTransaction { fn nonce(&self) -> u64 { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { nonce, .. } => *nonce, MockTransaction::Legacy { nonce, .. } => *nonce, MockTransaction::Eip1559 { nonce, .. } => *nonce, } @@ -316,6 +341,8 @@ impl PoolTransaction for MockTransaction { fn cost(&self) -> U256 { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => U256::from(0), MockTransaction::Legacy { gas_price, value, gas_limit, .. } => { U256::from(*gas_limit) * U256::from(*gas_price) + *value } @@ -335,6 +362,8 @@ impl PoolTransaction for MockTransaction { fn max_fee_per_gas(&self) -> Option { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => None, MockTransaction::Legacy { .. } => None, MockTransaction::Eip1559 { max_fee_per_gas, .. } => Some(*max_fee_per_gas), } @@ -342,6 +371,8 @@ impl PoolTransaction for MockTransaction { fn max_priority_fee_per_gas(&self) -> Option { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => None, MockTransaction::Legacy { .. } => None, MockTransaction::Eip1559 { max_priority_fee_per_gas, .. } => { Some(*max_priority_fee_per_gas) @@ -351,6 +382,8 @@ impl PoolTransaction for MockTransaction { fn kind(&self) -> &TransactionKind { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { to, .. } => to, MockTransaction::Legacy { to, .. } => to, MockTransaction::Eip1559 { to, .. } => to, } @@ -362,6 +395,8 @@ impl PoolTransaction for MockTransaction { fn tx_type(&self) -> u8 { match self { + #[cfg(feature = "optimism")] + MockTransaction::DepositTx { .. } => DEPOSIT_TX_TYPE, MockTransaction::Legacy { .. } => TxType::Legacy.into(), MockTransaction::Eip1559 { .. } => TxType::EIP1559.into(), } @@ -389,11 +424,12 @@ impl FromRecoveredTransaction for MockTransaction { is_system_transaction, input, }) => MockTransaction::DepositTx { - source_hash, - from, + nonce: 0u64, + hash: source_hash, + sender: from, to, mint, - value, + value: U256::from(value), gas_limit, is_system_transaction, input, diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 7b36e462833..f833e3e5df9 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -354,7 +354,7 @@ impl PoolTransaction for PooledTransaction { fn max_fee_per_gas(&self) -> Option { match &self.transaction.transaction { #[cfg(feature = "optimism")] - Transaction::Optimism(_) => None, + Transaction::Deposit(_) => None, Transaction::Legacy(_) => None, Transaction::Eip2930(_) => None, Transaction::Eip1559(tx) => Some(tx.max_fee_per_gas), @@ -366,6 +366,8 @@ impl PoolTransaction for PooledTransaction { /// This will return `None` for non-EIP1559 transactions fn max_priority_fee_per_gas(&self) -> Option { match &self.transaction.transaction { + #[cfg(feature = "optimism")] + Transaction::Deposit(_) => None, Transaction::Legacy(_) => None, Transaction::Eip2930(_) => None, Transaction::Eip1559(tx) => Some(tx.max_priority_fee_per_gas), @@ -397,6 +399,14 @@ impl PoolTransaction for PooledTransaction { impl FromRecoveredTransaction for PooledTransaction { fn from_recovered_transaction(tx: TransactionSignedEcRecovered) -> Self { let (cost, effective_gas_price) = match &tx.transaction { + #[cfg(feature = "optimism")] + Transaction::Deposit(t) => { + // TODO: fix this gas price estimate + let gas_price = U256::from(0); + let cost = U256::from(gas_price) * U256::from(t.gas_limit) + U256::from(t.value); + let effective_gas_price = 0u128; + (cost, effective_gas_price) + } Transaction::Legacy(t) => { let cost = U256::from(t.gas_price) * U256::from(t.gas_limit) + U256::from(t.value); let effective_gas_price = t.gas_price; From 5a150e7b3debdf4160b7fd3f899b93d66ff2aa32 Mon Sep 17 00:00:00 2001 From: clabby Date: Mon, 27 Feb 2023 09:05:01 -0500 Subject: [PATCH 8/9] Move feature flags below comments --- crates/primitives/src/chain/spec.rs | 8 ++++---- crates/primitives/src/hardfork.rs | 4 ++-- crates/primitives/src/transaction/mod.rs | 16 ++++++++-------- crates/primitives/src/transaction/tx_type.rs | 2 +- crates/rpc/rpc-types/src/eth/engine.rs | 6 +++--- crates/transaction-pool/src/test_utils/mock.rs | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index b3b5be9889c..e9798f78f06 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -125,14 +125,14 @@ pub struct ChainSpec { /// The active hard forks and their activation conditions pub hardforks: BTreeMap, - #[cfg(feature = "optimism")] /// Optimism configuration + #[cfg(feature = "optimism")] pub optimism: Option, } +/// Optimism configuration. #[cfg(feature = "optimism")] #[derive(Serialize, Deserialize, Debug, Clone)] -/// Optimism configuration. pub struct OptimismConfig { /// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) pub eip_1559_elasticity: u64, @@ -469,15 +469,15 @@ impl ChainSpecBuilder { self } - #[cfg(feature = "optimism")] /// Enable Bedrock at genesis + #[cfg(feature = "optimism")] pub fn bedrock_activated(mut self) -> Self { self.hardforks.insert(Hardfork::Bedrock, ForkCondition::Block(0)); self } - #[cfg(feature = "optimism")] /// Enable Bedrock at genesis + #[cfg(feature = "optimism")] pub fn regolith_activated(mut self) -> Self { self.hardforks.insert(Hardfork::Regolith, ForkCondition::Timestamp(0)); self diff --git a/crates/primitives/src/hardfork.rs b/crates/primitives/src/hardfork.rs index cc5d384faeb..0c3942ebd9d 100644 --- a/crates/primitives/src/hardfork.rs +++ b/crates/primitives/src/hardfork.rs @@ -39,11 +39,11 @@ pub enum Hardfork { Paris, /// Shanghai. Shanghai, - #[cfg(feature = "optimism")] /// Bedrock. - Bedrock, #[cfg(feature = "optimism")] + Bedrock, /// Regolith + #[cfg(feature = "optimism")] Regolith, } diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index d154e635c9b..7725675fc46 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -179,8 +179,8 @@ pub enum Transaction { Eip2930(TxEip2930), /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). Eip1559(TxEip1559), - #[cfg(feature = "optimism")] /// Deposit transaction. + #[cfg(feature = "optimism")] Deposit(TxDeposit), } @@ -255,8 +255,8 @@ impl Transaction { Transaction::Legacy(TxLegacy { nonce, .. }) => *nonce, Transaction::Eip2930(TxEip2930 { nonce, .. }) => *nonce, Transaction::Eip1559(TxEip1559 { nonce, .. }) => *nonce, - #[cfg(feature = "optimism")] // Deposit transactions don't have a nonce, so they default to zero. + #[cfg(feature = "optimism")] Transaction::Deposit(_) => 0, } } @@ -278,9 +278,9 @@ impl Transaction { Transaction::Legacy(TxLegacy { gas_price, .. }) | Transaction::Eip2930(TxEip2930 { gas_price, .. }) => *gas_price, Transaction::Eip1559(TxEip1559 { max_fee_per_gas, .. }) => *max_fee_per_gas, - #[cfg(feature = "optimism")] // Deposit transactions buy their L2 gas on L1 and, as such, the L2 gas is not // refundable. + #[cfg(feature = "optimism")] Transaction::Deposit(_) => 0, } } @@ -310,9 +310,9 @@ impl Transaction { } } - #[cfg(feature = "optimism")] /// Returns the source hash of the transaction, which uniquely identifies its source. /// If the transaction is not a deposit transaction, this will always return `H256::zero()`. + #[cfg(feature = "optimism")] pub fn source_hash(&self) -> H256 { match self { Transaction::Deposit(TxDeposit { source_hash, .. }) => *source_hash, @@ -320,9 +320,9 @@ impl Transaction { } } - #[cfg(feature = "optimism")] /// Returns the amount of ETH locked up on L1 that will be minted on L2. If the transaction /// is not a deposit transaction, this will always return `None`. + #[cfg(feature = "optimism")] pub fn mint(&self) -> Option { match self { Transaction::Deposit(TxDeposit { mint, .. }) => *mint, @@ -330,9 +330,9 @@ impl Transaction { } } - #[cfg(feature = "optimism")] /// Returns whether or not the transaction is a system transaction. If the transaction /// is not a deposit transaction, this will always return `false`. + #[cfg(feature = "optimism")] pub fn is_system_transaction(&self) -> bool { match self { Transaction::Deposit(TxDeposit { is_system_transaction, .. }) => *is_system_transaction, @@ -812,9 +812,9 @@ impl TransactionSigned { let tx_type = *data.first().ok_or(DecodeError::InputTooShort)?; data.advance(1); - #[cfg(feature = "optimism")] // If the transaction is a deposit, we need to first ensure that the version // byte is correct. + #[cfg(feature = "optimism")] if tx_type == DEPOSIT_TX_TYPE { let version = *data.first().ok_or(DecodeError::InputTooShort)?; if version != DEPOSIT_VERSION { @@ -831,9 +831,9 @@ impl TransactionSigned { // length of tx encoding = tx type byte (size = 1) + length of header + payload length let tx_length = 1 + header.length() + header.payload_length; - #[cfg(feature = "optimism")] // If the transaction is a deposit, we need to add one to the length to account for the // version byte. + #[cfg(feature = "optimism")] let tx_length = if tx_type == DEPOSIT_TX_TYPE { tx_length + 1 } else { tx_length }; // decode common fields diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index ca7f2ebd6bd..0115f7ea6ff 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -12,8 +12,8 @@ pub enum TxType { EIP2930 = 1_isize, /// Transaction with Priority fee EIP1559 = 2_isize, - #[cfg(feature = "optimism")] /// OP Deposit transaction. + #[cfg(feature = "optimism")] DEPOSIT = 126_isize, } diff --git a/crates/rpc/rpc-types/src/eth/engine.rs b/crates/rpc/rpc-types/src/eth/engine.rs index e8be77f3adc..548ed16645b 100644 --- a/crates/rpc/rpc-types/src/eth/engine.rs +++ b/crates/rpc/rpc-types/src/eth/engine.rs @@ -126,19 +126,19 @@ pub struct PayloadAttributes { #[serde(default, skip_serializing_if = "Option::is_none")] pub withdrawals: Option>, - #[cfg(feature = "optimism")] /// Transactions is a field for rollups: the transactions list is forced into the block + #[cfg(feature = "optimism")] #[serde(default, skip_serializing_if = "Option::is_none")] pub transactions: Option>, - #[cfg(feature = "optimism")] /// If true, the no transactions are taken out of the tx-pool, only transactions from the above /// Transactions list will be included. + #[cfg(feature = "optimism")] #[serde(default, skip_serializing_if = "Option::is_none")] pub no_tx_pool: Option, - #[cfg(feature = "optimism")] /// If set, this sets the exact gas limit the block produced with. + #[cfg(feature = "optimism")] #[serde(default, skip_serializing_if = "Option::is_none")] pub gas_limit: Option, } diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index ebdf9841770..422d5af6dc4 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -342,7 +342,7 @@ impl PoolTransaction for MockTransaction { fn cost(&self) -> U256 { match self { #[cfg(feature = "optimism")] - MockTransaction::DepositTx { .. } => U256::from(0), + MockTransaction::DepositTx { .. } => U256::ZERO, MockTransaction::Legacy { gas_price, value, gas_limit, .. } => { U256::from(*gas_limit) * U256::from(*gas_price) + *value } From b8c452a5ba17f11098bf313c4635bdf5aade945c Mon Sep 17 00:00:00 2001 From: clabby Date: Mon, 27 Feb 2023 09:14:05 -0500 Subject: [PATCH 9/9] Doc auto link --- crates/primitives/src/transaction/optimism.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/primitives/src/transaction/optimism.rs b/crates/primitives/src/transaction/optimism.rs index 31c272555fc..faad6908d48 100644 --- a/crates/primitives/src/transaction/optimism.rs +++ b/crates/primitives/src/transaction/optimism.rs @@ -52,7 +52,7 @@ impl TxDeposit { } /// Encodes only the transaction's fields into the desired buffer, without a RLP header. - /// https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#the-deposited-transaction-type + /// pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { self.source_hash.encode(out); self.from.encode(out);