Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
15ff007
feat: deposit tx
rkrasiuk Feb 26, 2023
28bfaaa
chainspec and forks
rkrasiuk Feb 26, 2023
c760918
feat: payload attributes op fields
rkrasiuk Feb 26, 2023
15be115
small fixes
refcell Feb 27, 2023
b761db0
Small changes to the deposit tx primitive
clabby Feb 27, 2023
968c2bf
more small fixes
refcell Feb 27, 2023
1c17ad8
compiles
refcell Feb 27, 2023
74cee5d
Move feature flags below comments
clabby Feb 27, 2023
bd71db3
Doc auto link
clabby Feb 27, 2023
ce41d79
WIP: OP Goerli genesis
clabby Mar 5, 2023
e803e07
Signature fix
clabby Mar 5, 2023
e53eb20
TEMP: Expose some CLI items
clabby Mar 19, 2023
98c173c
Resolve conflicts
clabby Mar 19, 2023
1bf2b08
Allow gaslimit to be set by the EngineAPI caller on OP
clabby Mar 19, 2023
8105ddd
Add Optimism EIP1559 elasticity multiplier / max base fee change deno…
clabby Mar 19, 2023
c99732f
feat: executor deposits
merklefruit Jun 11, 2023
6266b9f
feat: receipts, l1 cost wip
merklefruit Jun 11, 2023
0d793f8
chore: small fixes
merklefruit Jun 11, 2023
5b1b620
wip: transact() optimism changes
merklefruit Jun 12, 2023
2adfe43
chore: minor changes related to optimism execution
merklefruit Jun 12, 2023
891b841
wip: removed receipts changes + improved gas handling
merklefruit Jun 17, 2023
64df5ee
chore: cleanup
merklefruit Jun 18, 2023
f6d77a7
chore: system_tx and is_success method
merklefruit Jun 19, 2023
2cf460e
feat: refactoring: separated optimism feature + added routing fees to…
merklefruit Jun 20, 2023
3e2082c
fix: fee vault calc
merklefruit Jun 20, 2023
4960aaa
fix: increment balance via executor function
merklefruit Jun 20, 2023
db6d315
chore: minor fixes
merklefruit Jun 21, 2023
f9b1aa2
feat: parse l1 block info from l2 block
merklefruit Jun 28, 2023
49e54fb
chore: removed default trait
merklefruit Jun 28, 2023
759be83
chore: set deposit gas to 0 always
merklefruit Jun 29, 2023
5c93e35
Start resolving conflicts
clabby Jul 8, 2023
cb1c654
More conflict resolution / updates
clabby Jul 9, 2023
c4d38de
Reimplement @merklefruit's changes
clabby Jul 9, 2023
d701355
:broom:
clabby Jul 9, 2023
171b13b
chore: removed useless import
merklefruit Jul 9, 2023
59e9deb
fix build failures with optimism feature
roberto-bayardo Jul 19, 2023
2e56cbc
Fix feature flag
clabby Jul 19, 2023
1382ab2
Start Engine API / block building updates
clabby Jul 9, 2023
4a21b13
Rebase on upstream
clabby Jul 16, 2023
89be4a8
Fix build
clabby Jul 16, 2023
f84cf33
Move gas limit check
clabby Jul 18, 2023
03f6195
Merge in main
refcell Jul 26, 2023
657575b
Merge branch 'clabby/op-reth' into clabby/engine-api-mods
refcell Jul 26, 2023
da7f9a5
Fix lints:
refcell Jul 26, 2023
19a69f0
Fix duplicate branch arm
refcell Jul 26, 2023
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
45 changes: 24 additions & 21 deletions crates/consensus/beacon/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,27 +995,30 @@ where
// forkchoiceState.headBlockHash and identified via buildProcessId value if
// payloadAttributes is not null and the forkchoice state has been updated successfully.
// The build process is specified in the Payload building section.
let attributes = PayloadBuilderAttributes::new(state.head_block_hash, attrs);

// send the payload to the builder and return the receiver for the pending payload id,
// initiating payload job is handled asynchronously
let pending_payload_id = self.payload_builder.send_new_payload(attributes);

// Client software MUST respond to this method call in the following way:
// {
// payloadStatus: {
// status: VALID,
// latestValidHash: forkchoiceState.headBlockHash,
// validationError: null
// },
// payloadId: buildProcessId
// }
//
// if the payload is deemed VALID and the build process has begun.
OnForkChoiceUpdated::updated_with_pending_payload_id(
PayloadStatus::new(PayloadStatusEnum::Valid, Some(state.head_block_hash)),
pending_payload_id,
)
match PayloadBuilderAttributes::try_new(state.head_block_hash, attrs) {
Ok(attributes) => {
// send the payload to the builder and return the receiver for the pending payload
// id, initiating payload job is handled asynchronously
let pending_payload_id = self.payload_builder.send_new_payload(attributes);

// Client software MUST respond to this method call in the following way:
// {
// payloadStatus: {
// status: VALID,
// latestValidHash: forkchoiceState.headBlockHash,
// validationError: null
// },
// payloadId: buildProcessId
// }
//
// if the payload is deemed VALID and the build process has begun.
OnForkChoiceUpdated::updated_with_pending_payload_id(
PayloadStatus::new(PayloadStatusEnum::Valid, Some(state.head_block_hash)),
pending_payload_id,
)
}
Err(_) => OnForkChoiceUpdated::invalid_payload_attributes(),
}
}

/// When the Consensus layer receives a new block via the consensus gossip protocol,
Expand Down
3 changes: 2 additions & 1 deletion crates/payload/basic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ optimism = [
"reth-primitives/optimism",
"reth-revm/optimism",
"reth-transaction-pool/optimism",
"reth-provider/optimism"
"reth-provider/optimism",
"reth-payload-builder/optimism"
]
21 changes: 21 additions & 0 deletions crates/payload/basic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,8 +755,22 @@ where

let base_fee = initialized_block_env.basefee.to::<u64>();
let block_number = initialized_block_env.number.to::<u64>();

#[cfg(not(feature = "optimism"))]
let block_gas_limit: u64 = initialized_block_env.gas_limit.try_into().unwrap_or(u64::MAX);

#[cfg(feature = "optimism")]
let mut block_gas_limit: u64 = initialized_block_env.gas_limit.try_into().unwrap_or(u64::MAX);

#[cfg(feature = "optimism")]
{
if let Some(gas_limit) = attributes.gas_limit {
block_gas_limit = gas_limit;
}
// TODO(clabby): configure the gas limit of pending blocks with the miner gas limit config
// when using optimism
}

let WithdrawalsOutcome { withdrawals_root, withdrawals } = commit_withdrawals(
&mut db,
&mut post_state,
Expand Down Expand Up @@ -786,7 +800,14 @@ where
gas_limit: block_gas_limit,
difficulty: U256::ZERO,
gas_used: 0,
#[cfg(not(feature = "optimism"))]
extra_data: extra_data.into(),
#[cfg(feature = "optimism")]
extra_data: if chain_spec.optimism.is_none() {
extra_data.into()
} else {
Default::default()
},
};

let block = Block { header, body: vec![], ommers: vec![], withdrawals };
Expand Down
63 changes: 58 additions & 5 deletions crates/payload/builder/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

use reth_primitives::{Address, ChainSpec, Header, SealedBlock, Withdrawal, H256, U256};
use reth_revm_primitives::config::revm_spec_by_timestamp_after_merge;
use reth_rlp::Encodable;
use reth_rlp::{DecodeError, Encodable};
use reth_rpc_types::engine::{
ExecutionPayload, ExecutionPayloadEnvelope, PayloadAttributes, PayloadId,
};
use revm_primitives::{BlockEnv, CfgEnv};

#[cfg(feature = "optimism")]
use reth_primitives::TransactionSigned;
#[cfg(feature = "optimism")]
use reth_rlp::Decodable;

/// Contains the built payload.
///
/// According to the [engine API specification](https://github.com/ethereum/execution-apis/blob/main/src/engine/README.md) the execution layer should build the initial version of the payload with an empty transaction set and then keep update it in order to maximize the revenue.
Expand Down Expand Up @@ -88,6 +93,15 @@ pub struct PayloadBuilderAttributes {
pub prev_randao: H256,
/// Withdrawals for the generated payload
pub withdrawals: Vec<Withdrawal>,
/// NoTxPool option for the generated payload
#[cfg(feature = "optimism")]
pub no_tx_pool: bool,
/// Transactions for the generated payload
#[cfg(feature = "optimism")]
pub transactions: Vec<TransactionSigned>,
/// The gas limit for the generated payload
#[cfg(feature = "optimism")]
pub gas_limit: Option<u64>,
}

// === impl PayloadBuilderAttributes ===
Expand All @@ -96,16 +110,36 @@ impl PayloadBuilderAttributes {
/// Creates a new payload builder for the given parent block and the attributes.
///
/// Derives the unique [PayloadId] for the given parent and attributes
pub fn new(parent: H256, attributes: PayloadAttributes) -> Self {
pub fn try_new(parent: H256, attributes: PayloadAttributes) -> Result<Self, DecodeError> {
#[cfg(feature = "optimism")]
let transactions = attributes
.transactions
.as_ref()
.unwrap_or(&Vec::default())
.iter()
.map(|tx| TransactionSigned::decode(&mut &tx[..]))
.collect::<Result<_, _>>()?;

#[cfg(not(feature = "optimism"))]
let id = payload_id(&parent, &attributes);
Self {

#[cfg(feature = "optimism")]
let id = payload_id(&parent, &attributes, &transactions);

Ok(Self {
id,
parent,
timestamp: attributes.timestamp.as_u64(),
suggested_fee_recipient: attributes.suggested_fee_recipient,
prev_randao: attributes.prev_randao,
withdrawals: attributes.withdrawals.unwrap_or_default(),
}
#[cfg(feature = "optimism")]
no_tx_pool: attributes.no_tx_pool.unwrap_or_default(),
#[cfg(feature = "optimism")]
transactions,
#[cfg(feature = "optimism")]
gas_limit: attributes.gas_limit,
})
}

/// Returns the configured [CfgEnv] and [BlockEnv] for the targeted payload (that has the
Expand Down Expand Up @@ -149,7 +183,11 @@ impl PayloadBuilderAttributes {
/// Generates the payload id for the configured payload
///
/// Returns an 8-byte identifier by hashing the payload components with sha256 hash.
pub(crate) fn payload_id(parent: &H256, attributes: &PayloadAttributes) -> PayloadId {
pub(crate) fn payload_id(
parent: &H256,
attributes: &PayloadAttributes,
#[cfg(feature = "optimism")] txs: &Vec<TransactionSigned>,
) -> PayloadId {
use sha2::Digest;
let mut hasher = sha2::Sha256::new();
hasher.update(parent.as_bytes());
Expand All @@ -161,6 +199,21 @@ pub(crate) fn payload_id(parent: &H256, attributes: &PayloadAttributes) -> Paylo
withdrawals.encode(&mut buf);
hasher.update(buf);
}

#[cfg(feature = "optimism")]
{
let no_tx_pool = attributes.no_tx_pool.unwrap_or_default();
if no_tx_pool || !txs.is_empty() {
hasher.update([no_tx_pool as u8]);
hasher.update(txs.len().to_be_bytes());
txs.iter().for_each(|tx| hasher.update(tx.hash()));
}

if let Some(gas_limit) = attributes.gas_limit {
hasher.update(gas_limit.to_be_bytes());
}
}

let out = hasher.finalize();
PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
}
7 changes: 7 additions & 0 deletions crates/payload/builder/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,13 @@ where
if this.contains_payload(id) {
warn!(%id, parent = ?attr.parent, "Payload job already in progress, ignoring.");
} else {
// Don't start the payload job if there is no tx pool to pull from.
#[cfg(feature = "optimism")]
if attr.no_tx_pool {
let _ = tx.send(res);
continue
}

// no job for this payload yet, create one
match this.generator.new_payload_job(attr) {
Ok(job) => {
Expand Down
1 change: 0 additions & 1 deletion crates/revm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ once_cell = "1.17.0"

[features]
optimism = ["reth-primitives/optimism", "reth-revm-primitives/optimism"]

128 changes: 120 additions & 8 deletions crates/revm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,127 @@ where
let mut cumulative_gas_used = 0;
let mut post_state = PostState::with_tx_capacity(block.number, block.body.len());
for (transaction, sender) in block.body.iter().zip(senders) {
// The sum of the transaction’s gas limit, Tg, and the gas utilised in this block prior,
// must be no greater than the block’s gasLimit.
let block_available_gas = block.header.gas_limit - cumulative_gas_used;
if transaction.gas_limit() > block_available_gas {
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit: transaction.gas_limit(),
block_available_gas,
#[cfg(feature = "optimism")]
{
let db = self.db();
let l1_cost = l1_block_info.calculate_tx_l1_cost(transaction);

let sender_account =
db.load_account(sender).map_err(|_| BlockExecutionError::ProviderError)?;
let old_sender_info = to_reth_acc(&sender_account.info);

if let Some(m) = transaction.mint() {
// Add balance to the caler account equal to the minted amount.
// Note: This is unconditional, and will not be reverted if the tx fails
// (unless the block can't be built at all due to gas limit constraints)
sender_account.info.balance += U256::from(m);
}

// Check if the sender balance can cover the L1 cost.
// Deposits pay for their gas directly on L1 so they are exempt from the L2 tx fee.
if !transaction.is_deposit() {
if sender_account.info.balance.cmp(&l1_cost) == std::cmp::Ordering::Less {
return Err(BlockExecutionError::InsufficientFundsForL1Cost {
have: sender_account.info.balance.to::<u64>(),
want: l1_cost.to::<u64>(),
})
}

// Safely take l1_cost from sender (the rest will be deducted by the
// internal EVM execution and included in result.gas_used())
// TODO: need to handle calls with `disable_balance_check` flag set?
sender_account.info.balance -= l1_cost;
}

let new_sender_info = to_reth_acc(&sender_account.info);
post_state.change_account(block.number, sender, old_sender_info, new_sender_info);

// Execute transaction.
let ResultAndState { result, state } = self.transact(transaction, sender)?;

if transaction.is_deposit() && !result.is_success() {
// If the Deposited transaction failed, the deposit must still be included.
// In this case, we need to increment the sender nonce and disregard the
// state changes. The transaction is also recorded as using all gas.
let db = self.db();
let sender_account =
db.load_account(sender).map_err(|_| BlockExecutionError::ProviderError)?;
let old_sender_info = to_reth_acc(&sender_account.info);
sender_account.info.nonce += 1;
let new_sender_info = to_reth_acc(&sender_account.info);

post_state.change_account(
block.number,
sender,
old_sender_info,
new_sender_info,
);
if !transaction.is_system_transaction() {
cumulative_gas_used += transaction.gas_limit();
}

post_state.add_receipt(
block.number,
Receipt {
tx_type: transaction.tx_type(),
success: false,
cumulative_gas_used,
logs: vec![],
deposit_nonce: Some(transaction.nonce()),
},
);
continue
}

// commit changes
self.commit_changes(
block.number,
state,
self.chain_spec.fork(Hardfork::SpuriousDragon).active_at_block(block.number),
&mut post_state,
);

if !transaction.is_system_transaction() {
// After Regolith, deposits are reported as using the actual gas used instead of
// all the gas. System transactions are not reported as using any gas.
cumulative_gas_used += result.gas_used()
}
.into())

// Route the l1 cost and base fee to the appropriate optimism vaults
self.increment_account_balance(
block.number,
optimism::l1_cost_recipient(),
l1_cost,
&mut post_state,
)?;
self.increment_account_balance(
block.number,
optimism::base_fee_recipient(),
U256::from(
block
.base_fee_per_gas
.unwrap_or_default()
.saturating_mul(result.gas_used()),
),
&mut post_state,
)?;

// cast revm logs to reth logs
let logs = result.logs().into_iter().map(into_reth_log).collect();

// Push transaction changeset and calculate header bloom filter for receipt.
post_state.add_receipt(
block.number,
Receipt {
tx_type: transaction.tx_type(),
// Success flag was added in `EIP-658: Embedding transaction status code in
// receipts`.
success: result.is_success(),
cumulative_gas_used,
logs,
deposit_nonce: Some(transaction.nonce()),
},
);
}

#[cfg(feature = "optimism")]
Expand Down
5 changes: 5 additions & 0 deletions crates/rpc/rpc-engine-api/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ where
attrs.timestamp.as_u64(),
attrs.withdrawals.is_some(),
)?;

#[cfg(feature = "optimism")]
if attrs.gas_limit.is_none() && self.inner.chain_spec.optimism.is_some() {
return Err(EngineApiError::MissingGasLimitInPayloadAttributes)
}
}
Ok(self.inner.beacon_consensus.fork_choice_updated(state, payload_attrs).await?)
}
Expand Down
5 changes: 1 addition & 4 deletions crates/rpc/rpc-types/src/eth/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ pub struct TxGasAndReward {

impl PartialOrd for TxGasAndReward {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
// compare only the reward
// see:
// <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/eth/gasprice/feehistory.go#L85>
self.reward.partial_cmp(&other.reward)
Some(self.cmp(other))
}
}

Expand Down