Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion crates/op-rbuilder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ moka = "0.12"
http = "1.0"
sha3 = "0.10"
hex = "0.4"
ureq = "2.10"
reqwest = "0.12.23"
k256 = "0.13.4"

rollup-boost = { git = "http://github.com/flashbots/rollup-boost", rev = "b86af43969557bee18f17ec1d6bcd3e984f910b2" }
Expand All @@ -136,6 +136,9 @@ tar = { version = "0.4", optional = true }
ctor = { version = "0.4.2", optional = true }
rlimit = { version = "0.10", optional = true }
macros = { path = "src/tests/framework/macros", optional = true }
hyper = { version = "1.7.0", features = ["http1"], optional = true }
hyper-util = { version = "0.1.11", optional = true }
http-body-util = { version = "0.1.3", optional = true }
testcontainers = "0.24.0"
dirs-next = "2.0.0"

Expand All @@ -157,6 +160,9 @@ reth-ipc = { workspace = true }
reth-node-builder = { workspace = true, features = ["test-utils"] }
ctor = "0.4.2"
rlimit = { version = "0.10" }
hyper = { version = "1.7.0", features = ["http1"] }
hyper-util = { version = "0.1.11" }
http-body-util = { version = "0.1.3" }

[features]
default = ["jemalloc"]
Expand Down
23 changes: 16 additions & 7 deletions crates/op-rbuilder/src/builders/builder_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloy_consensus::TxEip1559;
use alloy_eips::{Encodable2718, eip7623::TOTAL_COST_FLOOR_PER_TOKEN};
use alloy_evm::Database;
use alloy_primitives::{
Address, B256, Log, TxKind,
Address, B256, Log, TxKind, U256,
map::foldhash::{HashSet, HashSetExt},
};
use core::fmt::Debug;
Expand All @@ -13,9 +13,7 @@ use reth_node_api::PayloadBuilderError;
use reth_optimism_primitives::OpTransactionSigned;
use reth_primitives::Recovered;
use reth_provider::{ProviderError, StateProvider};
use reth_revm::{
State, database::StateProviderDatabase, db::states::bundle_state::BundleRetention,
};
use reth_revm::{State, database::StateProviderDatabase};
use revm::{
DatabaseCommit,
context::result::{EVMError, ResultAndState},
Expand Down Expand Up @@ -57,6 +55,9 @@ pub enum BuilderTransactionError {
/// Signature signing fails
#[error("failed to sign transaction: {0}")]
SigningError(secp256k1::Error),
/// Invalid tx errors during evm execution.
#[error("invalid transaction error {0}")]
InvalidTransactionError(Box<dyn core::error::Error + Send + Sync>),
/// Unrecoverable error during evm execution.
#[error("evm execution error {0}")]
EvmExecutionError(Box<dyn core::error::Error + Send + Sync>),
Expand Down Expand Up @@ -187,7 +188,6 @@ pub trait BuilderTransactions<ExtraCtx: Debug + Default = ()>: Debug {
.map_err(|err| BuilderTransactionError::EvmExecutionError(Box::new(err)))?;

evm.db_mut().commit(state);
evm.db_mut().merge_transitions(BundleRetention::Reverts);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was it doing there?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

evm.db_mut().merge_transitions(BundleRetention::Reverts); was used to record points to revert the simulation state to a previous state. But we changed the implementation to just recreate a new state for every simulation run

}

Ok(simulation_state)
Expand Down Expand Up @@ -283,7 +283,7 @@ impl BuilderTxBase {
}
}

pub(crate) fn get_nonce(
pub fn get_nonce(
db: &mut State<impl Database>,
address: Address,
) -> Result<u64, BuilderTransactionError> {
Expand All @@ -292,6 +292,15 @@ pub(crate) fn get_nonce(
.map_err(|_| BuilderTransactionError::AccountLoadFailed(address))
}

pub(crate) fn log_exists(logs: &[Log], topic: &B256) -> bool {
pub fn get_balance(
db: &mut State<impl Database>,
address: Address,
) -> Result<U256, BuilderTransactionError> {
db.load_cache_account(address)
.map(|acc| acc.account_info().unwrap_or_default().balance)
.map_err(|_| BuilderTransactionError::AccountLoadFailed(address))
}

pub fn log_exists(logs: &[Log], topic: &B256) -> bool {
logs.iter().any(|log| log.topics().first() == Some(topic))
}
2 changes: 1 addition & 1 deletion crates/op-rbuilder/src/builders/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
}
if exclude_reverting_txs {
log_txn(TxnExecutionResult::RevertedAndExcluded);
info!(target: "payload_builder", tx_hash = ?tx.tx_hash(), "skipping reverted transaction");
info!(target: "payload_builder", tx_hash = ?tx.tx_hash(), result = ?result, "skipping reverted transaction");
best_txs.mark_invalid(tx.signer(), tx.nonce());
continue;
} else {
Expand Down
5 changes: 4 additions & 1 deletion crates/op-rbuilder/src/builders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ mod flashblocks;
mod generator;
mod standard;

pub use builder_tx::{BuilderTransactionCtx, BuilderTransactionError, BuilderTransactions};
pub use builder_tx::{
BuilderTransactionCtx, BuilderTransactionError, BuilderTransactions, get_balance, get_nonce,
log_exists,
};
pub use context::OpPayloadBuilderCtx;
pub use flashblocks::FlashblocksBuilder;
pub use standard::StandardBuilder;
Expand Down
14 changes: 12 additions & 2 deletions crates/op-rbuilder/src/builders/standard/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,15 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
// 4. if mem pool transactions are requested we execute them

// gas reserved for builder tx
let builder_txs = builder_tx.add_builder_txs(&state_provider, &mut info, ctx, db, true)?;
let builder_txs =
match builder_tx.add_builder_txs(&state_provider, &mut info, ctx, db, true) {
Ok(builder_txs) => builder_txs,
Err(e) => {
error!(target: "payload_builder", "Error adding builder txs to block: {}", e);
vec![]
}
};

let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
let block_gas_limit = ctx.block_gas_limit().saturating_sub(builder_tx_gas);
if block_gas_limit == 0 {
Expand Down Expand Up @@ -394,7 +402,9 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
}

// Add builder tx to the block
builder_tx.add_builder_txs(&state_provider, &mut info, ctx, db, false)?;
if let Err(e) = builder_tx.add_builder_txs(&state_provider, &mut info, ctx, db, false) {
error!(target: "payload_builder", "Error adding builder txs to fallback block: {}", e);
};

let state_merge_start_time = Instant::now();

Expand Down
16 changes: 14 additions & 2 deletions crates/op-rbuilder/src/flashtestations/args.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use alloy_primitives::{Address, U256, utils::parse_ether};
use clap::Parser;
use reth_optimism_cli::commands::Commands;

use crate::tx_signer::Signer;
use crate::{args::Cli, tx_signer::Signer};

/// Parameters for Flashtestations configuration
/// The names in the struct are prefixed with `flashtestations`
#[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)]
#[derive(Debug, Clone, PartialEq, Eq, clap::Args)]
pub struct FlashtestationsArgs {
/// When set to true, the builder will initiate the flashtestations
/// workflow within the bootstrapping and block building process.
Expand Down Expand Up @@ -91,3 +93,13 @@ pub struct FlashtestationsArgs {
)]
pub builder_proof_version: u8,
}

impl Default for FlashtestationsArgs {
fn default() -> Self {
let args = Cli::parse_from(["dummy", "node"]);
let Commands::Node(node_command) = args.command else {
unreachable!()
};
node_command.ext.flashtestations
}
}
45 changes: 22 additions & 23 deletions crates/op-rbuilder/src/flashtestations/attestation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::io::Read;
use reqwest::Client;
use tracing::info;
use ureq;

const DEBUG_QUOTE_SERVICE_URL: &str = "http://ns31695324.ip-141-94-163.eu:10080/attest";

Expand All @@ -12,55 +11,55 @@ pub struct AttestationConfig {
/// The URL of the quote provider
pub quote_provider: Option<String>,
}

/// Trait for attestation providers
pub trait AttestationProvider {
fn get_attestation(&self, report_data: [u8; 64]) -> eyre::Result<Vec<u8>>;
}

/// Remote attestation provider
#[derive(Debug, Clone)]
pub struct RemoteAttestationProvider {
client: Client,
service_url: String,
}

impl RemoteAttestationProvider {
pub fn new(service_url: String) -> Self {
Self { service_url }
let client = Client::new();
Self {
client,
service_url,
}
}
}

impl AttestationProvider for RemoteAttestationProvider {
fn get_attestation(&self, report_data: [u8; 64]) -> eyre::Result<Vec<u8>> {
impl RemoteAttestationProvider {
pub async fn get_attestation(&self, report_data: [u8; 64]) -> eyre::Result<Vec<u8>> {
let report_data_hex = hex::encode(report_data);
let url = format!("{}/{}", self.service_url, report_data_hex);

info!(target: "flashtestations", url = url, "fetching quote in debug mode");

let response = ureq::get(&url)
let response = self
.client
.get(&url)
.timeout(std::time::Duration::from_secs(10))
.call()?;

let mut body = Vec::new();
response.into_reader().read_to_end(&mut body)?;
.send()
.await?
.error_for_status()?;
let body = response.bytes().await?.to_vec();

Ok(body)
}
}

pub fn get_attestation_provider(
config: AttestationConfig,
) -> Box<dyn AttestationProvider + Send + Sync> {
pub fn get_attestation_provider(config: AttestationConfig) -> RemoteAttestationProvider {
if config.debug {
Box::new(RemoteAttestationProvider::new(
RemoteAttestationProvider::new(
config
.quote_provider
.unwrap_or(DEBUG_QUOTE_SERVICE_URL.to_string()),
))
)
} else {
Box::new(RemoteAttestationProvider::new(
RemoteAttestationProvider::new(
config
.quote_provider
.expect("remote quote provider must be specified when not in debug mode"),
))
)
}
}
95 changes: 95 additions & 0 deletions crates/op-rbuilder/src/flashtestations/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,98 @@
use alloy_sol_types::{Error, sol};
use op_revm::OpHaltReason;

// https://github.com/flashbots/flashtestations/commit/7cc7f68492fe672a823dd2dead649793aac1f216
sol!(
#[sol(rpc, abi)]
#[derive(Debug)]
interface IFlashtestationRegistry {
function registerTEEService(bytes calldata rawQuote, bytes calldata extendedRegistrationData) external;

/// @notice Emitted when a TEE service is registered
/// @param teeAddress The address of the TEE service
/// @param rawQuote The raw quote from the TEE device
/// @param alreadyExists Whether the TEE service is already registered
event TEEServiceRegistered(address indexed teeAddress, bytes rawQuote, bool alreadyExists);

/// @notice Emitted when the attestation contract is the 0x0 address
error InvalidAttestationContract();
/// @notice Emitted when the signature is expired because the deadline has passed
error ExpiredSignature(uint256 deadline);
/// @notice Emitted when the quote is invalid according to the Automata DCAP Attestation contract
error InvalidQuote(bytes output);
/// @notice Emitted when the report data length is too short
error InvalidReportDataLength(uint256 length);
/// @notice Emitted when the registration data hash does not match the expected hash
error InvalidRegistrationDataHash(bytes32 expected, bytes32 received);
/// @notice Emitted when the byte size is exceeded
error ByteSizeExceeded(uint256 size);
/// @notice Emitted when the TEE service is already registered when registering
error TEEServiceAlreadyRegistered(address teeAddress);
/// @notice Emitted when the signer doesn't match the TEE address
error SignerMustMatchTEEAddress(address signer, address teeAddress);
/// @notice Emitted when the TEE service is not registered
error TEEServiceNotRegistered(address teeAddress);
/// @notice Emitted when the TEE service is already invalid when trying to invalidate a TEE registration
error TEEServiceAlreadyInvalid(address teeAddress);
/// @notice Emitted when the TEE service is still valid when trying to invalidate a TEE registration
error TEEIsStillValid(address teeAddress);
/// @notice Emitted when the nonce is invalid when verifying a signature
error InvalidNonce(uint256 expected, uint256 provided);
}

#[sol(rpc, abi)]
#[derive(Debug)]
interface IBlockBuilderPolicy {
function verifyBlockBuilderProof(uint8 version, bytes32 blockContentHash) external;

/// @notice Emitted when a block builder proof is successfully verified
/// @param caller The address that called the verification function (TEE address)
/// @param workloadId The workload identifier of the TEE
/// @param version The flashtestation protocol version used
/// @param blockContentHash The hash of the block content
/// @param commitHash The git commit hash associated with the workload
event BlockBuilderProofVerified(
address caller, bytes32 workloadId, uint8 version, bytes32 blockContentHash, string commitHash
);

/// @notice Emitted when the registry is the 0x0 address
error InvalidRegistry();
/// @notice Emitted when a workload to be added is already in the policy
error WorkloadAlreadyInPolicy();
/// @notice Emitted when a workload to be removed is not in the policy
error WorkloadNotInPolicy();
/// @notice Emitted when the address is not in the approvedWorkloads mapping
error UnauthorizedBlockBuilder(address caller);
/// @notice Emitted when the nonce is invalid
error InvalidNonce(uint256 expected, uint256 provided);
/// @notice Emitted when the commit hash is empty
error EmptyCommitHash();
/// @notice Emitted when the source locators array is empty
error EmptySourceLocators();
}

struct BlockData {
bytes32 parentHash;
uint256 blockNumber;
uint256 timestamp;
bytes32[] transactionHashes;
}

type WorkloadId is bytes32;
);

#[derive(Debug, thiserror::Error)]
pub enum FlashtestationRevertReason {
#[error("flashtestation registry error: {0:?}")]
FlashtestationRegistry(IFlashtestationRegistry::IFlashtestationRegistryErrors),
#[error("block builder policy error: {0:?}")]
BlockBuilderPolicy(IBlockBuilderPolicy::IBlockBuilderPolicyErrors),
#[error("unknown revert: {0} err: {1}")]
Unknown(String, Error),
#[error("halt: {0:?}")]
Halt(OpHaltReason),
}

pub mod args;
pub mod attestation;
pub mod service;
Expand Down
Loading
Loading