Capella eip 4844 cleanup (#3652)

* add capella gossip boiler plate

* get everything compiling

Co-authored-by: realbigsean <sean@sigmaprime.io
Co-authored-by: Mark Mackey <mark@sigmaprime.io>

* small cleanup

* small cleanup

* cargo fix + some test cleanup

* improve block production

* add fixme for potential panic

Co-authored-by: Mark Mackey <mark@sigmaprime.io>
This commit is contained in:
realbigsean
2022-10-26 15:15:26 -04:00
committed by GitHub
parent 221c433d62
commit 137f230344
52 changed files with 1392 additions and 630 deletions

View File

@@ -12,7 +12,10 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use types::{EthSpec, ExecutionBlockHash, ExecutionPayload, Hash256, Uint256};
use types::{
EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge,
Hash256, Uint256,
};
const GAS_LIMIT: u64 = 16384;
const GAS_USED: u64 = GAS_LIMIT - 1;
@@ -28,21 +31,21 @@ impl<T: EthSpec> Block<T> {
pub fn block_number(&self) -> u64 {
match self {
Block::PoW(block) => block.block_number,
Block::PoS(payload) => payload.block_number,
Block::PoS(payload) => payload.block_number(),
}
}
pub fn parent_hash(&self) -> ExecutionBlockHash {
match self {
Block::PoW(block) => block.parent_hash,
Block::PoS(payload) => payload.parent_hash,
Block::PoS(payload) => payload.parent_hash(),
}
}
pub fn block_hash(&self) -> ExecutionBlockHash {
match self {
Block::PoW(block) => block.block_hash,
Block::PoS(payload) => payload.block_hash,
Block::PoS(payload) => payload.block_hash(),
}
}
@@ -63,33 +66,18 @@ impl<T: EthSpec> Block<T> {
timestamp: block.timestamp,
},
Block::PoS(payload) => ExecutionBlock {
block_hash: payload.block_hash,
block_number: payload.block_number,
parent_hash: payload.parent_hash,
block_hash: payload.block_hash(),
block_number: payload.block_number(),
parent_hash: payload.parent_hash(),
total_difficulty,
timestamp: payload.timestamp,
timestamp: payload.timestamp(),
},
}
}
pub fn as_execution_block_with_tx(&self) -> Option<ExecutionBlockWithTransactions<T>> {
match self {
Block::PoS(payload) => Some(ExecutionBlockWithTransactions {
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
transactions: vec![],
}),
Block::PoS(payload) => Some(payload.clone().into()),
Block::PoW(_) => None,
}
}
@@ -283,7 +271,9 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
// Update the block hash after modifying the block
match &mut block {
Block::PoW(b) => b.block_hash = ExecutionBlockHash::from_root(b.tree_hash_root()),
Block::PoS(b) => b.block_hash = ExecutionBlockHash::from_root(b.tree_hash_root()),
Block::PoS(b) => {
*b.block_hash_mut() = ExecutionBlockHash::from_root(b.tree_hash_root())
}
}
self.block_hashes.insert(block_number, block.block_hash());
self.blocks.insert(block.block_hash(), block);
@@ -295,7 +285,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
}
pub fn new_payload(&mut self, payload: ExecutionPayload<T>) -> PayloadStatusV1 {
let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash) {
let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash()) {
parent
} else {
return PayloadStatusV1 {
@@ -305,7 +295,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
};
};
if payload.block_number != parent.block_number() + 1 {
if payload.block_number() != parent.block_number() + 1 {
return PayloadStatusV1 {
status: PayloadStatusV1Status::Invalid,
latest_valid_hash: Some(parent.block_hash()),
@@ -313,8 +303,8 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
};
}
let valid_hash = payload.block_hash;
self.pending_payloads.insert(payload.block_hash, payload);
let valid_hash = payload.block_hash();
self.pending_payloads.insert(payload.block_hash(), payload);
PayloadStatusV1 {
status: PayloadStatusV1Status::Valid,
@@ -379,24 +369,52 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
let id = payload_id_from_u64(self.next_payload_id);
self.next_payload_id += 1;
let mut execution_payload = ExecutionPayload {
parent_hash: forkchoice_state.head_block_hash,
fee_recipient: attributes.suggested_fee_recipient,
receipts_root: Hash256::repeat_byte(42),
state_root: Hash256::repeat_byte(43),
logs_bloom: vec![0; 256].into(),
prev_randao: attributes.prev_randao,
block_number: parent.block_number() + 1,
gas_limit: GAS_LIMIT,
gas_used: GAS_USED,
timestamp: attributes.timestamp,
extra_data: "block gen was here".as_bytes().to_vec().into(),
base_fee_per_gas: Uint256::one(),
block_hash: ExecutionBlockHash::zero(),
transactions: vec![].into(),
// FIXME: think about how to test different forks
let mut execution_payload = match &attributes {
PayloadAttributes::V1(pa) => ExecutionPayload::Merge(ExecutionPayloadMerge {
parent_hash: forkchoice_state.head_block_hash,
fee_recipient: pa.suggested_fee_recipient,
receipts_root: Hash256::repeat_byte(42),
state_root: Hash256::repeat_byte(43),
logs_bloom: vec![0; 256].into(),
prev_randao: pa.prev_randao,
block_number: parent.block_number() + 1,
gas_limit: GAS_LIMIT,
gas_used: GAS_USED,
timestamp: pa.timestamp,
extra_data: "block gen was here".as_bytes().to_vec().into(),
base_fee_per_gas: Uint256::one(),
block_hash: ExecutionBlockHash::zero(),
transactions: vec![].into(),
}),
PayloadAttributes::V2(pa) => {
ExecutionPayload::Capella(ExecutionPayloadCapella {
parent_hash: forkchoice_state.head_block_hash,
fee_recipient: pa.suggested_fee_recipient,
receipts_root: Hash256::repeat_byte(42),
state_root: Hash256::repeat_byte(43),
logs_bloom: vec![0; 256].into(),
prev_randao: pa.prev_randao,
block_number: parent.block_number() + 1,
gas_limit: GAS_LIMIT,
gas_used: GAS_USED,
timestamp: pa.timestamp,
extra_data: "block gen was here".as_bytes().to_vec().into(),
base_fee_per_gas: Uint256::one(),
block_hash: ExecutionBlockHash::zero(),
transactions: vec![].into(),
withdrawals: pa
.withdrawals
.iter()
.cloned()
.map(Into::into)
.collect::<Vec<_>>()
.into(),
})
}
};
execution_payload.block_hash =
*execution_payload.block_hash_mut() =
ExecutionBlockHash::from_root(execution_payload.tree_hash_root());
self.payload_ids.insert(id, execution_payload);

View File

@@ -75,12 +75,12 @@ pub async fn handle_rpc<T: EthSpec>(
}
}
ENGINE_NEW_PAYLOAD_V1 => {
let request: JsonExecutionPayloadV1<T> = get_param(params, 0)?;
let request: JsonExecutionPayload<T> = get_param(params, 0)?;
let (static_response, should_import) =
if let Some(mut response) = ctx.static_new_payload_response.lock().clone() {
if response.status.status == PayloadStatusV1Status::Valid {
response.status.latest_valid_hash = Some(request.block_hash)
response.status.latest_valid_hash = Some(*request.block_hash())
}
(Some(response.status), response.should_import)
@@ -112,11 +112,11 @@ pub async fn handle_rpc<T: EthSpec>(
.get_payload(&id)
.ok_or_else(|| format!("no payload for id {:?}", id))?;
Ok(serde_json::to_value(JsonExecutionPayloadV1::from(response)).unwrap())
Ok(serde_json::to_value(JsonExecutionPayload::from(response)).unwrap())
}
ENGINE_FORKCHOICE_UPDATED_V1 => {
let forkchoice_state: JsonForkChoiceStateV1 = get_param(params, 0)?;
let payload_attributes: Option<JsonPayloadAttributesV1> = get_param(params, 1)?;
let payload_attributes: Option<JsonPayloadAttributes> = get_param(params, 1)?;
let head_block_hash = forkchoice_state.head_block_hash;

View File

@@ -1,5 +1,5 @@
use crate::test_utils::DEFAULT_JWT_SECRET;
use crate::{Config, ExecutionLayer, PayloadAttributes};
use crate::{Config, ExecutionLayer, PayloadAttributes, PayloadAttributesV1};
use async_trait::async_trait;
use eth2::types::{BlockId, StateId, ValidatorId};
use eth2::{BeaconNodeHttpClient, Timeouts};
@@ -287,11 +287,12 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
.get_randao_mix(head_state.current_epoch())
.map_err(convert_err)?;
let payload_attributes = PayloadAttributes {
// FIXME: think about proper fork here
let payload_attributes = PayloadAttributes::V1(PayloadAttributesV1 {
timestamp,
prev_randao: *prev_randao,
suggested_fee_recipient: fee_recipient,
};
});
self.el
.insert_proposer(slot, head_block_root, val_index, payload_attributes)
@@ -315,6 +316,7 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
)
.await
.map_err(convert_err)?
.to_payload()
.to_execution_payload_header();
let json_payload = serde_json::to_string(&payload).map_err(convert_err)?;

View File

@@ -1,7 +1,7 @@
use crate::{
test_utils::{
MockServer, DEFAULT_BUILDER_THRESHOLD_WEI, DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK,
DEFAULT_TERMINAL_DIFFICULTY,
Block, MockServer, DEFAULT_BUILDER_THRESHOLD_WEI, DEFAULT_JWT_SECRET,
DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_DIFFICULTY,
},
Config, *,
};
@@ -99,20 +99,37 @@ impl<T: EthSpec> MockExecutionLayer<T> {
finalized_hash: None,
};
// FIXME: this is just best guess for how to deal with forks here..
let payload_attributes = match &latest_execution_block {
&Block::PoS(ref pos_block) => match pos_block {
&ExecutionPayload::Merge(_) => PayloadAttributes::V1(PayloadAttributesV1 {
timestamp,
prev_randao,
suggested_fee_recipient: Address::repeat_byte(42),
}),
&ExecutionPayload::Capella(_) | &ExecutionPayload::Eip4844(_) => {
PayloadAttributes::V2(PayloadAttributesV2 {
timestamp,
prev_randao,
suggested_fee_recipient: Address::repeat_byte(42),
// FIXME: think about adding withdrawals here..
withdrawals: vec![],
})
}
},
// I guess a PoW blocks means we should use Merge?
&Block::PoW(_) => PayloadAttributes::V1(PayloadAttributesV1 {
timestamp,
prev_randao,
suggested_fee_recipient: Address::repeat_byte(42),
}),
};
// Insert a proposer to ensure the fork choice updated command works.
let slot = Slot::new(0);
let validator_index = 0;
self.el
.insert_proposer(
slot,
head_block_root,
validator_index,
PayloadAttributes {
timestamp,
prev_randao,
suggested_fee_recipient: Address::repeat_byte(42),
},
)
.insert_proposer(slot, head_block_root, validator_index, payload_attributes)
.await;
self.el
@@ -132,7 +149,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
slot,
chain_health: ChainHealth::Healthy,
};
let payload = self
let payload: ExecutionPayload<T> = self
.el
.get_payload::<FullPayload<T>>(
parent_hash,
@@ -145,12 +162,14 @@ impl<T: EthSpec> MockExecutionLayer<T> {
)
.await
.unwrap()
.execution_payload;
let block_hash = payload.block_hash;
assert_eq!(payload.parent_hash, parent_hash);
assert_eq!(payload.block_number, block_number);
assert_eq!(payload.timestamp, timestamp);
assert_eq!(payload.prev_randao, prev_randao);
.to_payload()
.into();
let block_hash = payload.block_hash();
assert_eq!(payload.parent_hash(), parent_hash);
assert_eq!(payload.block_number(), block_number);
assert_eq!(payload.timestamp(), timestamp);
assert_eq!(payload.prev_randao(), prev_randao);
// Ensure the payload cache is empty.
assert!(self
@@ -175,12 +194,13 @@ impl<T: EthSpec> MockExecutionLayer<T> {
)
.await
.unwrap()
.execution_payload_header;
assert_eq!(payload_header.block_hash, block_hash);
assert_eq!(payload_header.parent_hash, parent_hash);
assert_eq!(payload_header.block_number, block_number);
assert_eq!(payload_header.timestamp, timestamp);
assert_eq!(payload_header.prev_randao, prev_randao);
.to_payload();
assert_eq!(payload_header.block_hash(), block_hash);
assert_eq!(payload_header.parent_hash(), parent_hash);
assert_eq!(payload_header.block_number(), block_number);
assert_eq!(payload_header.timestamp(), timestamp);
assert_eq!(payload_header.prev_randao(), prev_randao);
// Ensure the payload cache has the correct payload.
assert_eq!(