add trusted setup, query different version of EL endpoint at each fork

This commit is contained in:
realbigsean 2022-12-07 12:01:21 -05:00
parent 2704955b2e
commit e5f26516bd
No known key found for this signature in database
GPG Key ID: B372B64D866BF8CC
11 changed files with 4325 additions and 46 deletions

View File

@ -67,6 +67,8 @@ pub struct Config {
pub network: network::NetworkConfig, pub network: network::NetworkConfig,
pub chain: beacon_chain::ChainConfig, pub chain: beacon_chain::ChainConfig,
pub eth1: eth1::Config, pub eth1: eth1::Config,
//FIXME(sean)
#[serde(skip)]
pub execution_layer: Option<execution_layer::Config>, pub execution_layer: Option<execution_layer::Config>,
pub trusted_setup_file: Option<PathBuf>, pub trusted_setup_file: Option<PathBuf>,
pub http_api: http_api::Config, pub http_api: http_api::Config,

View File

@ -31,10 +31,12 @@ pub const ETH_SYNCING_TIMEOUT: Duration = Duration::from_secs(1);
pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1"; pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1";
pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2"; pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2";
pub const ENGINE_NEW_PAYLOAD_V3: &str = "engine_newPayloadV3";
pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8); pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8);
pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1"; pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2"; pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2";
pub const ENGINE_GET_PAYLOAD_V3: &str = "engine_getPayloadV3";
pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2); pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);
pub const ENGINE_GET_BLOBS_BUNDLE_V1: &str = "engine_getBlobsBundleV1"; pub const ENGINE_GET_BLOBS_BUNDLE_V1: &str = "engine_getBlobsBundleV1";
@ -42,6 +44,8 @@ pub const ENGINE_GET_BLOBS_BUNDLE_TIMEOUT: Duration = Duration::from_secs(2);
pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1"; pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1";
pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2"; pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2";
//FIXME(sean)
pub const ENGINE_FORKCHOICE_UPDATED_V3: &str = "engine_forkchoiceUpdatedV2";
pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8); pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
pub const ENGINE_EXCHANGE_TRANSITION_CONFIGURATION_V1: &str = pub const ENGINE_EXCHANGE_TRANSITION_CONFIGURATION_V1: &str =
@ -708,6 +712,23 @@ impl HttpJsonRpc {
Ok(response.into()) Ok(response.into())
} }
pub async fn new_payload_v3<T: EthSpec>(
&self,
execution_payload: ExecutionPayload<T>,
) -> Result<PayloadStatusV1, Error> {
let params = json!([JsonExecutionPayloadV2::try_from(execution_payload)?]);
let response: JsonPayloadStatusV1 = self
.rpc_request(
ENGINE_NEW_PAYLOAD_V3,
params,
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
Ok(response.into())
}
pub async fn get_payload_v1<T: EthSpec>( pub async fn get_payload_v1<T: EthSpec>(
&self, &self,
fork_name: ForkName, fork_name: ForkName,
@ -744,6 +765,24 @@ impl HttpJsonRpc {
JsonExecutionPayload::V2(payload_v2).try_into_execution_payload(fork_name) JsonExecutionPayload::V2(payload_v2).try_into_execution_payload(fork_name)
} }
pub async fn get_payload_v3<T: EthSpec>(
&self,
fork_name: ForkName,
payload_id: PayloadId,
) -> Result<ExecutionPayload<T>, Error> {
let params = json!([JsonPayloadIdRequest::from(payload_id)]);
let payload_v2: JsonExecutionPayloadV2<T> = self
.rpc_request(
ENGINE_GET_PAYLOAD_V3,
params,
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
JsonExecutionPayload::V2(payload_v2).try_into_execution_payload(fork_name)
}
pub async fn get_blobs_bundle_v1<T: EthSpec>( pub async fn get_blobs_bundle_v1<T: EthSpec>(
&self, &self,
payload_id: PayloadId, payload_id: PayloadId,
@ -803,6 +842,27 @@ impl HttpJsonRpc {
Ok(response.into()) Ok(response.into())
} }
pub async fn forkchoice_updated_v3(
&self,
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
) -> Result<ForkchoiceUpdatedResponse, Error> {
let params = json!([
JsonForkchoiceStateV1::from(forkchoice_state),
payload_attributes.map(JsonPayloadAttributes::from)
]);
let response: JsonForkchoiceUpdatedV1Response = self
.rpc_request(
ENGINE_FORKCHOICE_UPDATED_V3,
params,
ENGINE_FORKCHOICE_UPDATED_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
Ok(response.into())
}
pub async fn exchange_transition_configuration_v1( pub async fn exchange_transition_configuration_v1(
&self, &self,
transition_configuration: TransitionConfigurationV1, transition_configuration: TransitionConfigurationV1,
@ -855,13 +915,10 @@ impl HttpJsonRpc {
&self, &self,
execution_payload: ExecutionPayload<T>, execution_payload: ExecutionPayload<T>,
) -> Result<PayloadStatusV1, Error> { ) -> Result<PayloadStatusV1, Error> {
let supported_apis = self.get_cached_supported_apis().await?; match execution_payload {
if supported_apis.new_payload_v2 { ExecutionPayload::Eip4844(_) => self.new_payload_v3(execution_payload).await,
self.new_payload_v2(execution_payload).await ExecutionPayload::Capella(_) => self.new_payload_v2(execution_payload).await,
} else if supported_apis.new_payload_v1 { ExecutionPayload::Merge(_) => self.new_payload_v1(execution_payload).await,
self.new_payload_v1(execution_payload).await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayload"))
} }
} }
@ -872,13 +929,11 @@ impl HttpJsonRpc {
fork_name: ForkName, fork_name: ForkName,
payload_id: PayloadId, payload_id: PayloadId,
) -> Result<ExecutionPayload<T>, Error> { ) -> Result<ExecutionPayload<T>, Error> {
let supported_apis = self.get_cached_supported_apis().await?; match fork_name {
if supported_apis.get_payload_v2 { ForkName::Eip4844 => self.get_payload_v3(fork_name, payload_id).await,
self.get_payload_v2(fork_name, payload_id).await ForkName::Capella => self.get_payload_v2(fork_name, payload_id).await,
} else if supported_apis.new_payload_v1 { ForkName::Merge => self.get_payload_v1(fork_name, payload_id).await,
self.get_payload_v1(fork_name, payload_id).await _ => Err(Error::RequiredMethodUnsupported("engine_getPayload")),
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayload"))
} }
} }
@ -886,23 +941,29 @@ impl HttpJsonRpc {
// forkchoice_updated that the execution engine supports // forkchoice_updated that the execution engine supports
pub async fn forkchoice_updated( pub async fn forkchoice_updated(
&self, &self,
fork_name: ForkName,
forkchoice_state: ForkchoiceState, forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>, payload_attributes: Option<PayloadAttributes>,
) -> Result<ForkchoiceUpdatedResponse, Error> { ) -> Result<ForkchoiceUpdatedResponse, Error> {
let supported_apis = self.get_cached_supported_apis().await?; match fork_name {
if supported_apis.forkchoice_updated_v2 { ForkName::Eip4844 => {
self.forkchoice_updated_v2(forkchoice_state, payload_attributes) self.forkchoice_updated_v3(forkchoice_state, payload_attributes)
.await
}
ForkName::Capella => {
self.forkchoice_updated_v2(forkchoice_state, payload_attributes)
.await
}
ForkName::Merge => {
self.forkchoice_updated_v1(
forkchoice_state,
payload_attributes
.map(|pa| pa.downgrade_to_v1())
.transpose()?,
)
.await .await
} else if supported_apis.forkchoice_updated_v1 { }
self.forkchoice_updated_v1( _ => Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated")),
forkchoice_state,
payload_attributes
.map(|pa| pa.downgrade_to_v1())
.transpose()?,
)
.await
} else {
Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated"))
} }
} }
} }

View File

@ -11,7 +11,7 @@ use std::sync::Arc;
use task_executor::TaskExecutor; use task_executor::TaskExecutor;
use tokio::sync::{watch, Mutex, RwLock}; use tokio::sync::{watch, Mutex, RwLock};
use tokio_stream::wrappers::WatchStream; use tokio_stream::wrappers::WatchStream;
use types::{Address, ExecutionBlockHash, Hash256}; use types::{Address, ExecutionBlockHash, ForkName, Hash256};
/// The number of payload IDs that will be stored for each `Engine`. /// The number of payload IDs that will be stored for each `Engine`.
/// ///
@ -114,7 +114,7 @@ pub struct Engine {
pub api: HttpJsonRpc, pub api: HttpJsonRpc,
payload_id_cache: Mutex<LruCache<PayloadIdCacheKey, PayloadId>>, payload_id_cache: Mutex<LruCache<PayloadIdCacheKey, PayloadId>>,
state: RwLock<State>, state: RwLock<State>,
latest_forkchoice_state: RwLock<Option<ForkchoiceState>>, latest_forkchoice_state: RwLock<Option<(ForkName, ForkchoiceState)>>,
executor: TaskExecutor, executor: TaskExecutor,
log: Logger, log: Logger,
} }
@ -153,13 +153,15 @@ impl Engine {
pub async fn notify_forkchoice_updated( pub async fn notify_forkchoice_updated(
&self, &self,
fork_name: ForkName,
forkchoice_state: ForkchoiceState, forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>, payload_attributes: Option<PayloadAttributes>,
log: &Logger, log: &Logger,
) -> Result<ForkchoiceUpdatedResponse, EngineApiError> { ) -> Result<ForkchoiceUpdatedResponse, EngineApiError> {
info!(log, "Notifying FCU"; "fork_name" => ?fork_name);
let response = self let response = self
.api .api
.forkchoice_updated(forkchoice_state, payload_attributes.clone()) .forkchoice_updated(fork_name, forkchoice_state, payload_attributes.clone())
.await?; .await?;
if let Some(payload_id) = response.payload_id { if let Some(payload_id) = response.payload_id {
@ -179,18 +181,18 @@ impl Engine {
Ok(response) Ok(response)
} }
async fn get_latest_forkchoice_state(&self) -> Option<ForkchoiceState> { async fn get_latest_forkchoice_state(&self) -> Option<(ForkName, ForkchoiceState)> {
*self.latest_forkchoice_state.read().await *self.latest_forkchoice_state.read().await
} }
pub async fn set_latest_forkchoice_state(&self, state: ForkchoiceState) { pub async fn set_latest_forkchoice_state(&self, fork_name: ForkName, state: ForkchoiceState) {
*self.latest_forkchoice_state.write().await = Some(state); *self.latest_forkchoice_state.write().await = Some((fork_name, state));
} }
async fn send_latest_forkchoice_state(&self) { async fn send_latest_forkchoice_state(&self) {
let latest_forkchoice_state = self.get_latest_forkchoice_state().await; let latest_forkchoice_state = self.get_latest_forkchoice_state().await;
if let Some(forkchoice_state) = latest_forkchoice_state { if let Some((fork_name, forkchoice_state)) = latest_forkchoice_state {
if forkchoice_state.head_block_hash == ExecutionBlockHash::zero() { if forkchoice_state.head_block_hash == ExecutionBlockHash::zero() {
debug!( debug!(
self.log, self.log,
@ -204,11 +206,16 @@ impl Engine {
self.log, self.log,
"Issuing forkchoiceUpdated"; "Issuing forkchoiceUpdated";
"forkchoice_state" => ?forkchoice_state, "forkchoice_state" => ?forkchoice_state,
"fork_name" => ?fork_name,
); );
// For simplicity, payload attributes are never included in this call. It may be // For simplicity, payload attributes are never included in this call. It may be
// reasonable to include them in the future. // reasonable to include them in the future.
if let Err(e) = self.api.forkchoice_updated(forkchoice_state, None).await { if let Err(e) = self
.api
.forkchoice_updated(fork_name, forkchoice_state, None)
.await
{
debug!( debug!(
self.log, self.log,
"Failed to issue latest head to engine"; "Failed to issue latest head to engine";

View File

@ -216,10 +216,11 @@ struct Inner<E: EthSpec> {
executor: TaskExecutor, executor: TaskExecutor,
payload_cache: PayloadCache<E>, payload_cache: PayloadCache<E>,
builder_profit_threshold: Uint256, builder_profit_threshold: Uint256,
spec: ChainSpec,
log: Logger, log: Logger,
} }
#[derive(Debug, Default, Clone, Serialize, Deserialize)] #[derive(Debug, Default, Clone)]
pub struct Config { pub struct Config {
/// Endpoint urls for EL nodes that are running the engine api. /// Endpoint urls for EL nodes that are running the engine api.
pub execution_endpoints: Vec<SensitiveUrl>, pub execution_endpoints: Vec<SensitiveUrl>,
@ -239,6 +240,7 @@ pub struct Config {
/// The minimum value of an external payload for it to be considered in a proposal. /// The minimum value of an external payload for it to be considered in a proposal.
pub builder_profit_threshold: u128, pub builder_profit_threshold: u128,
pub execution_timeout_multiplier: Option<u32>, pub execution_timeout_multiplier: Option<u32>,
pub spec: ChainSpec,
} }
/// Provides access to one execution engine and provides a neat interface for consumption by the /// Provides access to one execution engine and provides a neat interface for consumption by the
@ -261,6 +263,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
default_datadir, default_datadir,
builder_profit_threshold, builder_profit_threshold,
execution_timeout_multiplier, execution_timeout_multiplier,
spec,
} = config; } = config;
if urls.len() > 1 { if urls.len() > 1 {
@ -332,6 +335,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
executor, executor,
payload_cache: PayloadCache::default(), payload_cache: PayloadCache::default(),
builder_profit_threshold: Uint256::from(builder_profit_threshold), builder_profit_threshold: Uint256::from(builder_profit_threshold),
spec,
log, log,
}; };
@ -1007,6 +1011,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
let response = engine let response = engine
.notify_forkchoice_updated( .notify_forkchoice_updated(
current_fork,
fork_choice_state, fork_choice_state,
Some(payload_attributes.clone()), Some(payload_attributes.clone()),
self.log(), self.log(),
@ -1265,8 +1270,42 @@ impl<T: EthSpec> ExecutionLayer<T> {
finalized_block_hash, finalized_block_hash,
}; };
let fork_name = self
.inner
.spec
.fork_name_at_epoch(next_slot.epoch(T::slots_per_epoch()));
let epoch = next_slot.epoch(T::slots_per_epoch());
let eip4844_fork_epoch = self.inner.spec.eip4844_fork_epoch;
let capella_fork_epoch = self.inner.spec.capella_fork_epoch;
let bellatrix_fork_epoch = self.inner.spec.bellatrix_fork_epoch;
let altair_fork_epoch = self.inner.spec.altair_fork_epoch;
let genesis_slot = self.inner.spec.genesis_slot;
info!(
self.log(),
"fork name at slot";
"fork_name" => ?fork_name,
"next_slot" => ?next_slot,
"epoch" => ?epoch,
"eip4844_fork_epoch" => ?eip4844_fork_epoch,
"capella_fork_epoch" => ?capella_fork_epoch,
"bellatrix_fork_epoch" => ?bellatrix_fork_epoch,
"altair_fork_epoch" => ?altair_fork_epoch,
"genesis_slot" => ?genesis_slot,
);
// Dec 06 16:47:39.049 INFO fork name at slot
// genesis_slot: Slot(0),
// altair_fork_epoch: Some(Epoch(74240)),
// bellatrix_fork_epoch: Some(Epoch(144896)),
// capella_fork_epoch: Some(Epoch(18446744073709551615)),
// eip4844_fork_epoch: None, epoch: Epoch(0),
// next_slot: Slot(12), fork_name: Base, service: exec
self.engine() self.engine()
.set_latest_forkchoice_state(forkchoice_state) .set_latest_forkchoice_state(fork_name, forkchoice_state)
.await; .await;
let payload_attributes_ref = &payload_attributes; let payload_attributes_ref = &payload_attributes;
@ -1275,6 +1314,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
.request(|engine| async move { .request(|engine| async move {
engine engine
.notify_forkchoice_updated( .notify_forkchoice_updated(
fork_name,
forkchoice_state, forkchoice_state,
payload_attributes_ref.clone(), payload_attributes_ref.clone(),
self.log(), self.log(),

View File

@ -342,6 +342,7 @@ pub fn get_config<E: EthSpec>(
let execution_timeout_multiplier = let execution_timeout_multiplier =
clap_utils::parse_required(cli_args, "execution-timeout-multiplier")?; clap_utils::parse_required(cli_args, "execution-timeout-multiplier")?;
el_config.execution_timeout_multiplier = Some(execution_timeout_multiplier); el_config.execution_timeout_multiplier = Some(execution_timeout_multiplier);
el_config.spec = spec.clone();
// If `--execution-endpoint` is provided, we should ignore any `--eth1-endpoints` values and // If `--execution-endpoint` is provided, we should ignore any `--eth1-endpoints` values and
// use `--execution-endpoint` instead. Also, log a deprecation warning. // use `--execution-endpoint` instead. Also, log a deprecation warning.

View File

@ -14,12 +14,12 @@ use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use types::{BeaconStateMerge, ExecutionBlockHash};
use types::{ use types::{
test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Eth1Data, test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Eth1Data,
EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderMerge, Hash256, Keypair, PublicKey, EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderMerge, Hash256, Keypair, PublicKey,
Validator, Validator,
}; };
use types::{BeaconStateMerge, ExecutionBlockHash};
pub fn run<T: EthSpec>(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> { pub fn run<T: EthSpec>(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?; let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?;
@ -141,13 +141,10 @@ pub fn run<T: EthSpec>(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Resul
None None
}; };
let mut merge_state : types::BeaconState<T>=BeaconState::Merge(BeaconStateMerge::from_ssz_bytes(genesis_state_bytes.unwrap().as_ref()).unwrap());
upgrade_to_capella(&mut merge_state, &spec).unwrap();
let testnet = Eth2NetworkConfig { let testnet = Eth2NetworkConfig {
deposit_contract_deploy_block, deposit_contract_deploy_block,
boot_enr: Some(vec![]), boot_enr: Some(vec![]),
genesis_state_bytes: Some(merge_state.as_ssz_bytes()), genesis_state_bytes,
config: Config::from_chain_spec::<T>(&spec), config: Config::from_chain_spec::<T>(&spec),
}; };

View File

@ -62,4 +62,5 @@ exec $lighthouse_binary \
--disable-packet-filter \ --disable-packet-filter \
--target-peers $((BN_COUNT - 1)) \ --target-peers $((BN_COUNT - 1)) \
--execution-endpoint $execution_endpoint \ --execution-endpoint $execution_endpoint \
--trusted-setup-file ./trusted_setup.txt \
--execution-jwt $execution_jwt --execution-jwt $execution_jwt

View File

@ -12,8 +12,8 @@
"berlinBlock": 0, "berlinBlock": 0,
"londonBlock": 0, "londonBlock": 0,
"mergeNetsplitBlock": 0, "mergeNetsplitBlock": 0,
"shanghaiBlock": 0, "shanghaiTime": 1670428733,
"shardingForkBlock": 32, "shardingForkTime": 1670428829,
"terminalTotalDifficulty": 0 "terminalTotalDifficulty": 0
}, },
"alloc": { "alloc": {

View File

@ -50,3 +50,10 @@ lcli \
--node-count $BN_COUNT --node-count $BN_COUNT
echo Validators generated with keystore passwords at $DATADIR. echo Validators generated with keystore passwords at $DATADIR.
GENESIS_TIME=$(lcli pretty-ssz state_merge ~/.lighthouse/local-testnet/testnet/genesis.ssz | jq | grep -Po 'genesis_time": "\K.*\d')
CAPELLA_TIME=$((GENESIS_TIME + (CAPELLA_FORK_EPOCH * 32 * SECONDS_PER_SLOT)))
EIP4844_TIME=$((GENESIS_TIME + (EIP4844_FORK_EPOCH * 32 * SECONDS_PER_SLOT)))
sed -i 's/"shanghaiTime".*$/"shanghaiTime": '"$CAPELLA_TIME"',/g' genesis.json
sed -i 's/"shardingForkTime".*$/"shardingForkTime": '"$EIP4844_TIME"',/g' genesis.json

File diff suppressed because it is too large Load Diff

View File

@ -37,8 +37,8 @@ CHAIN_ID=4242
# Hard fork configuration # Hard fork configuration
ALTAIR_FORK_EPOCH=0 ALTAIR_FORK_EPOCH=0
BELLATRIX_FORK_EPOCH=0 BELLATRIX_FORK_EPOCH=0
CAPELLA_FORK_EPOCH=0 CAPELLA_FORK_EPOCH=1
EIP4844_FORK_EPOCH=1 EIP4844_FORK_EPOCH=2
TTD=0 TTD=0