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 chain: beacon_chain::ChainConfig,
pub eth1: eth1::Config,
//FIXME(sean)
#[serde(skip)]
pub execution_layer: Option<execution_layer::Config>,
pub trusted_setup_file: Option<PathBuf>,
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_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_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
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_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_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_EXCHANGE_TRANSITION_CONFIGURATION_V1: &str =
@ -708,6 +712,23 @@ impl HttpJsonRpc {
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>(
&self,
fork_name: ForkName,
@ -744,6 +765,24 @@ impl HttpJsonRpc {
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>(
&self,
payload_id: PayloadId,
@ -803,6 +842,27 @@ impl HttpJsonRpc {
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(
&self,
transition_configuration: TransitionConfigurationV1,
@ -855,13 +915,10 @@ impl HttpJsonRpc {
&self,
execution_payload: ExecutionPayload<T>,
) -> Result<PayloadStatusV1, Error> {
let supported_apis = self.get_cached_supported_apis().await?;
if supported_apis.new_payload_v2 {
self.new_payload_v2(execution_payload).await
} else if supported_apis.new_payload_v1 {
self.new_payload_v1(execution_payload).await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayload"))
match execution_payload {
ExecutionPayload::Eip4844(_) => self.new_payload_v3(execution_payload).await,
ExecutionPayload::Capella(_) => self.new_payload_v2(execution_payload).await,
ExecutionPayload::Merge(_) => self.new_payload_v1(execution_payload).await,
}
}
@ -872,13 +929,11 @@ impl HttpJsonRpc {
fork_name: ForkName,
payload_id: PayloadId,
) -> Result<ExecutionPayload<T>, Error> {
let supported_apis = self.get_cached_supported_apis().await?;
if supported_apis.get_payload_v2 {
self.get_payload_v2(fork_name, payload_id).await
} else if supported_apis.new_payload_v1 {
self.get_payload_v1(fork_name, payload_id).await
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayload"))
match fork_name {
ForkName::Eip4844 => self.get_payload_v3(fork_name, payload_id).await,
ForkName::Capella => self.get_payload_v2(fork_name, payload_id).await,
ForkName::Merge => self.get_payload_v1(fork_name, payload_id).await,
_ => Err(Error::RequiredMethodUnsupported("engine_getPayload")),
}
}
@ -886,23 +941,29 @@ impl HttpJsonRpc {
// forkchoice_updated that the execution engine supports
pub async fn forkchoice_updated(
&self,
fork_name: ForkName,
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
) -> Result<ForkchoiceUpdatedResponse, Error> {
let supported_apis = self.get_cached_supported_apis().await?;
if supported_apis.forkchoice_updated_v2 {
self.forkchoice_updated_v2(forkchoice_state, payload_attributes)
match fork_name {
ForkName::Eip4844 => {
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
} else if supported_apis.forkchoice_updated_v1 {
self.forkchoice_updated_v1(
forkchoice_state,
payload_attributes
.map(|pa| pa.downgrade_to_v1())
.transpose()?,
)
.await
} else {
Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated"))
}
_ => Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated")),
}
}
}

View File

@ -11,7 +11,7 @@ use std::sync::Arc;
use task_executor::TaskExecutor;
use tokio::sync::{watch, Mutex, RwLock};
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`.
///
@ -114,7 +114,7 @@ pub struct Engine {
pub api: HttpJsonRpc,
payload_id_cache: Mutex<LruCache<PayloadIdCacheKey, PayloadId>>,
state: RwLock<State>,
latest_forkchoice_state: RwLock<Option<ForkchoiceState>>,
latest_forkchoice_state: RwLock<Option<(ForkName, ForkchoiceState)>>,
executor: TaskExecutor,
log: Logger,
}
@ -153,13 +153,15 @@ impl Engine {
pub async fn notify_forkchoice_updated(
&self,
fork_name: ForkName,
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
log: &Logger,
) -> Result<ForkchoiceUpdatedResponse, EngineApiError> {
info!(log, "Notifying FCU"; "fork_name" => ?fork_name);
let response = self
.api
.forkchoice_updated(forkchoice_state, payload_attributes.clone())
.forkchoice_updated(fork_name, forkchoice_state, payload_attributes.clone())
.await?;
if let Some(payload_id) = response.payload_id {
@ -179,18 +181,18 @@ impl Engine {
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
}
pub async fn set_latest_forkchoice_state(&self, state: ForkchoiceState) {
*self.latest_forkchoice_state.write().await = Some(state);
pub async fn set_latest_forkchoice_state(&self, fork_name: ForkName, state: ForkchoiceState) {
*self.latest_forkchoice_state.write().await = Some((fork_name, state));
}
async fn send_latest_forkchoice_state(&self) {
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() {
debug!(
self.log,
@ -204,11 +206,16 @@ impl Engine {
self.log,
"Issuing forkchoiceUpdated";
"forkchoice_state" => ?forkchoice_state,
"fork_name" => ?fork_name,
);
// For simplicity, payload attributes are never included in this call. It may be
// 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!(
self.log,
"Failed to issue latest head to engine";

View File

@ -216,10 +216,11 @@ struct Inner<E: EthSpec> {
executor: TaskExecutor,
payload_cache: PayloadCache<E>,
builder_profit_threshold: Uint256,
spec: ChainSpec,
log: Logger,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[derive(Debug, Default, Clone)]
pub struct Config {
/// Endpoint urls for EL nodes that are running the engine api.
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.
pub builder_profit_threshold: u128,
pub execution_timeout_multiplier: Option<u32>,
pub spec: ChainSpec,
}
/// 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,
builder_profit_threshold,
execution_timeout_multiplier,
spec,
} = config;
if urls.len() > 1 {
@ -332,6 +335,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
executor,
payload_cache: PayloadCache::default(),
builder_profit_threshold: Uint256::from(builder_profit_threshold),
spec,
log,
};
@ -1007,6 +1011,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
let response = engine
.notify_forkchoice_updated(
current_fork,
fork_choice_state,
Some(payload_attributes.clone()),
self.log(),
@ -1265,8 +1270,42 @@ impl<T: EthSpec> ExecutionLayer<T> {
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()
.set_latest_forkchoice_state(forkchoice_state)
.set_latest_forkchoice_state(fork_name, forkchoice_state)
.await;
let payload_attributes_ref = &payload_attributes;
@ -1275,6 +1314,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
.request(|engine| async move {
engine
.notify_forkchoice_updated(
fork_name,
forkchoice_state,
payload_attributes_ref.clone(),
self.log(),

View File

@ -342,6 +342,7 @@ pub fn get_config<E: EthSpec>(
let execution_timeout_multiplier =
clap_utils::parse_required(cli_args, "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
// 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::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use types::{BeaconStateMerge, ExecutionBlockHash};
use types::{
test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Eth1Data,
EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderMerge, Hash256, Keypair, PublicKey,
Validator,
};
use types::{BeaconStateMerge, ExecutionBlockHash};
pub fn run<T: EthSpec>(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> {
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
};
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 {
deposit_contract_deploy_block,
boot_enr: Some(vec![]),
genesis_state_bytes: Some(merge_state.as_ssz_bytes()),
genesis_state_bytes,
config: Config::from_chain_spec::<T>(&spec),
};

View File

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

View File

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

View File

@ -50,3 +50,10 @@ lcli \
--node-count $BN_COUNT
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
ALTAIR_FORK_EPOCH=0
BELLATRIX_FORK_EPOCH=0
CAPELLA_FORK_EPOCH=0
EIP4844_FORK_EPOCH=1
CAPELLA_FORK_EPOCH=1
EIP4844_FORK_EPOCH=2
TTD=0