feat: add empty payload building support (#2346)

This commit is contained in:
Matthias Seitz
2023-04-23 22:21:33 +02:00
committed by GitHub
parent b8e92e09a0
commit 652bdaacd3
6 changed files with 106 additions and 20 deletions

View File

@ -15,7 +15,9 @@ use reth_payload_builder::{
};
use reth_primitives::{
bytes::{Bytes, BytesMut},
constants::{RETH_CLIENT_VERSION, SLOT_DURATION},
constants::{
EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, EMPTY_WITHDRAWALS, RETH_CLIENT_VERSION, SLOT_DURATION,
},
proofs, Block, BlockId, BlockNumberOrTag, ChainSpec, Header, IntoRecoveredTransaction, Receipt,
SealedBlock, EMPTY_OMMER_ROOT, U256,
};
@ -333,9 +335,17 @@ where
Pool: TransactionPool + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
{
fn best_payload(&self) -> Arc<BuiltPayload> {
// TODO if still not set, initialize empty block
self.best_payload.clone().unwrap()
fn best_payload(&self) -> Result<Arc<BuiltPayload>, PayloadBuilderError> {
if let Some(ref payload) = self.best_payload {
return Ok(payload.clone())
}
// No payload has been built yet, but we need to return something that the CL then can
// deliver, so we need to return an empty payload.
//
// Note: it is assumed that this is unlikely to happen, as the payload job is started right
// away and the first full block should have been built by the time CL is requesting the
// payload.
build_empty_payload(&self.client, self.config.clone()).map(Arc::new)
}
}
@ -357,6 +367,8 @@ impl Future for PendingPayload {
}
/// A marker that can be used to cancel a job.
///
/// If dropped, it will set the `cancelled` flag to true.
#[derive(Default, Clone)]
struct Cancelled(Arc<AtomicBool>);
@ -575,6 +587,65 @@ fn build_payload<Pool, Client>(
let _ = to_job.send(try_build(client, pool, config, cancel, best_payload));
}
/// Builds an empty payload without any transactions.
fn build_empty_payload<Client>(
client: &Client,
config: PayloadConfig,
) -> Result<BuiltPayload, PayloadBuilderError>
where
Client: StateProviderFactory,
{
// TODO this needs to access the _pending_ state of the parent block hash
let _state = client.latest()?;
let PayloadConfig {
initialized_block_env,
parent_block,
extra_data,
attributes,
initialized_cfg,
..
} = config;
let base_fee = initialized_block_env.basefee.to::<u64>();
let block_gas_limit: u64 = initialized_block_env.gas_limit.try_into().unwrap_or(u64::MAX);
let mut withdrawals_root = None;
let mut withdrawals = None;
if initialized_cfg.spec_id >= SpecId::SHANGHAI {
withdrawals_root = Some(EMPTY_WITHDRAWALS);
// set withdrawals
withdrawals = Some(attributes.withdrawals);
}
let header = Header {
parent_hash: parent_block.hash,
ommers_hash: EMPTY_OMMER_ROOT,
beneficiary: initialized_block_env.coinbase,
// TODO compute state root
state_root: Default::default(),
transactions_root: EMPTY_TRANSACTIONS,
withdrawals_root,
receipts_root: EMPTY_RECEIPTS,
logs_bloom: Default::default(),
timestamp: attributes.timestamp,
mix_hash: attributes.prev_randao,
nonce: 0,
base_fee_per_gas: Some(base_fee),
number: parent_block.number + 1,
gas_limit: block_gas_limit,
difficulty: U256::ZERO,
gas_used: 0,
extra_data: extra_data.into(),
};
let block = Block { header, body: vec![], ommers: vec![], withdrawals };
let sealed_block = block.seal_slow();
Ok(BuiltPayload::new(attributes.id, sealed_block, U256::ZERO))
}
/// Checks if the new payload is better than the current best.
///
/// This compares the total fees of the blocks, higher is better.