mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-27 17:53:42 +00:00
* Attestation superstruct changes for EIP 7549 (#5644)
* update
* experiment
* superstruct changes
* revert
* superstruct changes
* fix tests
* indexed attestation
* indexed attestation superstruct
* updated TODOs
* `superstruct` the `AttesterSlashing` (#5636)
* `superstruct` Attester Fork Variants
* Push a little further
* Deal with Encode / Decode of AttesterSlashing
* not so sure about this..
* Stop Encode/Decode Bounds from Propagating Out
* Tons of Changes..
* More Conversions to AttestationRef
* Add AsReference trait (#15)
* Add AsReference trait
* Fix some snafus
* Got it Compiling! :D
* Got Tests Building
* Get beacon chain tests compiling
---------
Co-authored-by: Michael Sproul <micsproul@gmail.com>
* Merge remote-tracking branch 'upstream/unstable' into electra_attestation_changes
* Make EF Tests Fork-Agnostic (#5713)
* Finish EF Test Fork Agnostic (#5714)
* Superstruct `AggregateAndProof` (#5715)
* Upgrade `superstruct` to `0.8.0`
* superstruct `AggregateAndProof`
* Merge remote-tracking branch 'sigp/unstable' into electra_attestation_changes
* cargo fmt
* Merge pull request #5726 from realbigsean/electra_attestation_changes
Merge unstable into Electra attestation changes
* process withdrawals updates
* cleanup withdrawals processing
* update `process_operations` deposit length check
* add apply_deposit changes
* add execution layer withdrawal request processing
* process deposit receipts
* add consolidation processing
* update process operations function
* exit updates
* clean up
* update slash_validator
* EIP7549 `get_attestation_indices` (#5657)
* get attesting indices electra impl
* fmt
* get tests to pass
* fmt
* fix some beacon chain tests
* fmt
* fix slasher test
* fmt got me again
* fix more tests
* fix tests
* Some small changes (#5739)
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* cargo fmt (#5740)
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* fix attestation verification
* Add new engine api methods
* Fix the versioning of v4 requests
* Handle new engine api methods in mock EL
* Note todo
* Fix todos
* Add support for electra fields in getPayloadBodies
* Add comments for potential versioning confusion
* Sketch op pool changes
* fix get attesting indices (#5742)
* fix get attesting indices
* better errors
* fix compile
* only get committee index once
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Ef test fixes (#5753)
* attestation related ef test fixes
* delete commented out stuff
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-engine-api
* Fix Aggregation Pool for Electra (#5754)
* Fix Aggregation Pool for Electra
* Remove Outdated Interface
* fix ssz (#5755)
* Get `electra_op_pool` up to date (#5756)
* fix get attesting indices (#5742)
* fix get attesting indices
* better errors
* fix compile
* only get committee index once
* Ef test fixes (#5753)
* attestation related ef test fixes
* delete commented out stuff
* Fix Aggregation Pool for Electra (#5754)
* Fix Aggregation Pool for Electra
* Remove Outdated Interface
* fix ssz (#5755)
---------
Co-authored-by: realbigsean <sean@sigmaprime.io>
* Revert "Get `electra_op_pool` up to date (#5756)" (#5757)
This reverts commit ab9e58aa3d.
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into electra_op_pool
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-engine-api
* Compute on chain aggregate impl (#5752)
* add compute_on_chain_agg impl to op pool changes
* fmt
* get op pool tests to pass
* update the naive agg pool interface (#5760)
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-engine-api
* Fix bugs in cross-committee aggregation
* Add comment to max cover optimisation
* Fix assert
* Electra epoch processing
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Merge pull request #5749 from sigp/electra_op_pool
Optimise Electra op pool aggregation
* don't fail on empty consolidations
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* update committee offset
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* update committee offset
* update committee offset
* only increment the state deposit index on old deposit flow
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* use correct max eb in epoch cache initialization
* drop initiate validator ordering optimization
* fix initiate exit for single pass
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* accept new payload v4 in mock el
* Fix Electra Fork Choice Tests (#5764)
* Fix Electra Fork Choice Tests (#5764)
* Fix Electra Fork Choice Tests (#5764)
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Fix Consolidation Sigs & Withdrawals
* Merge pull request #5766 from ethDreamer/two_fixes
Fix Consolidation Sigs & Withdrawals
* Merge branches 'block-processing-electra' and 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Fix ser/de
* Subscribe to the correct subnets for electra attestations (#5782)
* subscribe to the correct att subnets for electra
* subscribe to the correct att subnets for electra
* cargo fmt
* Subscribe to the correct subnets for electra attestations (#5782)
* subscribe to the correct att subnets for electra
* subscribe to the correct att subnets for electra
* cargo fmt
* Subscribe to the correct subnets for electra attestations (#5782)
* subscribe to the correct att subnets for electra
* subscribe to the correct att subnets for electra
* cargo fmt
* Subscribe to the correct subnets for electra attestations (#5782)
* subscribe to the correct att subnets for electra
* subscribe to the correct att subnets for electra
* cargo fmt
* update electra readiness with new endpoints
* fix slashing handling
* Fix Bug In Block Processing with 0x02 Credentials
* Merge remote-tracking branch 'upstream/unstable'
* Send unagg attestation based on fork
* Publish all aggregates
* just one more check bro plz..
* Merge pull request #5832 from ethDreamer/electra_attestation_changes_merge_unstable
Merge `unstable` into `electra_attestation_changes`
* Merge pull request #5835 from realbigsean/fix-validator-logic
Fix validator logic
* Merge pull request #5816 from realbigsean/electra-attestation-slashing-handling
Electra slashing handling
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* fix: serde rename camle case for execution payload body (#5846)
* Electra attestation changes rm decode impl (#5856)
* Remove Crappy Decode impl for Attestation
* Remove Inefficient Attestation Decode impl
* Implement Schema Upgrade / Downgrade
* Update beacon_node/beacon_chain/src/schema_change/migration_schema_v20.rs
Co-authored-by: Michael Sproul <micsproul@gmail.com>
---------
Co-authored-by: Michael Sproul <micsproul@gmail.com>
* Fix failing attestation tests and misc electra attestation cleanup (#5810)
* - get attestation related beacon chain tests to pass
- observed attestations are now keyed off of data + committee index
- rename op pool attestationref to compactattestationref
- remove unwraps in agg pool and use options instead
- cherry pick some changes from ef-tests-electra
* cargo fmt
* fix failing test
* Revert dockerfile changes
* make committee_index return option
* function args shouldnt be a ref to attestation ref
* fmt
* fix dup imports
---------
Co-authored-by: realbigsean <seananderson33@GMAIL.com>
* fix some todos (#5817)
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes
* add consolidations to merkle calc for inclusion proof
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Remove Duplicate KZG Commitment Merkle Proof Code (#5874)
* Remove Duplicate KZG Commitment Merkle Proof Code
* s/tree_lists/fields/
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* fix compile
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Fix slasher tests (#5906)
* Fix electra tests
* Add electra attestations to double vote tests
* Update superstruct to 0.8
* Merge remote-tracking branch 'origin/unstable' into electra_attestation_changes
* Small cleanup in slasher tests
* Clean up Electra observed aggregates (#5929)
* Use consistent key in observed_attestations
* Remove unwraps from observed aggregates
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes
* De-dup attestation constructor logic
* Remove unwraps in Attestation construction
* Dedup match_attestation_data
* Remove outdated TODO
* Use ForkName Ord in fork-choice tests
* Use ForkName Ord in BeaconBlockBody
* Make to_electra not fallible
* Remove TestRandom impl for IndexedAttestation
* Remove IndexedAttestation faulty Decode impl
* Drop TestRandom impl
* Add PendingAttestationInElectra
* Indexed att on disk (#35)
* indexed att on disk
* fix lints
* Update slasher/src/migrate.rs
Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>
---------
Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com>
Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>
* add electra fork enabled fn to ForkName impl (#36)
* add electra fork enabled fn to ForkName impl
* remove inadvertent file
* Update common/eth2/src/types.rs
Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>
* Dedup attestation constructor logic in attester cache
* Use if let Ok for committee_bits
* Dedup Attestation constructor code
* Diff reduction in tests
* Fix beacon_chain tests
* Diff reduction
* Use Ord for ForkName in pubsub
* Resolve into_attestation_and_indices todo
* Remove stale TODO
* Fix beacon_chain tests
* Test spec invariant
* Use electra_enabled in pubsub
* Remove get_indexed_attestation_from_signed_aggregate
* Use ok_or instead of if let else
* committees are sorted
* remove dup method `get_indexed_attestation_from_committees`
* Merge pull request #5940 from dapplion/electra_attestation_changes_lionreview
Electra attestations #5712 review
* update default persisted op pool deserialization
* ensure aggregate and proof uses serde untagged on ref
* Fork aware ssz static attestation tests
* Electra attestation changes from Lions review (#5971)
* dedup/cleanup and remove unneeded hashset use
* remove irrelevant TODOs
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes
* Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* Electra attestation changes sean review (#5972)
* instantiate empty bitlist in unreachable code
* clean up error conversion
* fork enabled bool cleanup
* remove a couple todos
* return bools instead of options in `aggregate` and use the result
* delete commented out code
* use map macros in simple transformations
* remove signers_disjoint_from
* get ef tests compiling
* get ef tests compiling
* update intentionally excluded files
* Avoid changing slasher schema for Electra
* Delete slasher schema v4
* Fix clippy
* Fix compilation of beacon_chain tests
* Update database.rs
* Update per_block_processing.rs
* Add electra lightclient types
* Update slasher/src/database.rs
* fix imports
* Merge pull request #5980 from dapplion/electra-lightclient
Add electra lightclient types
* Merge pull request #5975 from michaelsproul/electra-slasher-no-migration
Avoid changing slasher schema for Electra
* Update beacon_node/beacon_chain/src/attestation_verification.rs
* Update beacon_node/beacon_chain/src/attestation_verification.rs
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes
* Merge branch 'electra_attestation_changes' of https://github.com/realbigsean/lighthouse into block-processing-electra
* Merge branch 'block-processing-electra' of https://github.com/sigp/lighthouse into electra-epoch-proc
* Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
* The great renaming receipt -> request
* Address some more review comments
* Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra-engine-api
* Update beacon_node/beacon_chain/src/electra_readiness.rs
* Update consensus/types/src/chain_spec.rs
876 lines
31 KiB
Rust
876 lines
31 KiB
Rust
use crate::engines::ForkchoiceState;
|
|
use crate::http::{
|
|
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
|
|
ENGINE_GET_CLIENT_VERSION_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
|
|
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2,
|
|
ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2,
|
|
ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4,
|
|
};
|
|
use eth2::types::{
|
|
BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2,
|
|
SsePayloadAttributesV3,
|
|
};
|
|
use ethers_core::types::Transaction;
|
|
use ethers_core::utils::rlp;
|
|
use ethers_core::utils::rlp::{Decodable, Rlp};
|
|
use http::deposit_methods::RpcError;
|
|
pub use json_structures::{JsonWithdrawal, TransitionConfigurationV1};
|
|
use pretty_reqwest_error::PrettyReqwestError;
|
|
use reqwest::StatusCode;
|
|
use serde::{Deserialize, Serialize};
|
|
use strum::IntoStaticStr;
|
|
use superstruct::superstruct;
|
|
use types::execution_payload::{DepositRequests, WithdrawalRequests};
|
|
pub use types::{
|
|
Address, BeaconBlockRef, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader,
|
|
ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, Uint256, VariableList,
|
|
Withdrawal, Withdrawals,
|
|
};
|
|
use types::{
|
|
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
|
ExecutionPayloadElectra, KzgProofs,
|
|
};
|
|
use types::{Graffiti, GRAFFITI_BYTES_LEN};
|
|
|
|
pub mod auth;
|
|
pub mod http;
|
|
pub mod json_structures;
|
|
mod new_payload_request;
|
|
|
|
pub use new_payload_request::{
|
|
NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella,
|
|
NewPayloadRequestDeneb, NewPayloadRequestElectra,
|
|
};
|
|
|
|
use self::json_structures::{JsonDepositRequest, JsonWithdrawalRequest};
|
|
|
|
pub const LATEST_TAG: &str = "latest";
|
|
|
|
pub type PayloadId = [u8; 8];
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
HttpClient(PrettyReqwestError),
|
|
Auth(auth::Error),
|
|
BadResponse(String),
|
|
RequestFailed(String),
|
|
InvalidExecutePayloadResponse(&'static str),
|
|
JsonRpc(RpcError),
|
|
Json(serde_json::Error),
|
|
ServerMessage { code: i64, message: String },
|
|
Eip155Failure,
|
|
IsSyncing,
|
|
ExecutionBlockNotFound(ExecutionBlockHash),
|
|
ExecutionHeadBlockNotFound,
|
|
ParentHashEqualsBlockHash(ExecutionBlockHash),
|
|
PayloadIdUnavailable,
|
|
SszError(ssz_types::Error),
|
|
DeserializeWithdrawals(ssz_types::Error),
|
|
DeserializeDepositRequests(ssz_types::Error),
|
|
DeserializeWithdrawalRequests(ssz_types::Error),
|
|
BuilderApi(builder_client::Error),
|
|
IncorrectStateVariant,
|
|
RequiredMethodUnsupported(&'static str),
|
|
UnsupportedForkVariant(String),
|
|
InvalidClientVersion(String),
|
|
RlpDecoderError(rlp::DecoderError),
|
|
}
|
|
|
|
impl From<reqwest::Error> for Error {
|
|
fn from(e: reqwest::Error) -> Self {
|
|
if matches!(
|
|
e.status(),
|
|
Some(StatusCode::UNAUTHORIZED) | Some(StatusCode::FORBIDDEN)
|
|
) {
|
|
Error::Auth(auth::Error::InvalidToken)
|
|
} else {
|
|
Error::HttpClient(e.into())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<serde_json::Error> for Error {
|
|
fn from(e: serde_json::Error) -> Self {
|
|
Error::Json(e)
|
|
}
|
|
}
|
|
|
|
impl From<auth::Error> for Error {
|
|
fn from(e: auth::Error) -> Self {
|
|
Error::Auth(e)
|
|
}
|
|
}
|
|
|
|
impl From<builder_client::Error> for Error {
|
|
fn from(e: builder_client::Error) -> Self {
|
|
Error::BuilderApi(e)
|
|
}
|
|
}
|
|
|
|
impl From<rlp::DecoderError> for Error {
|
|
fn from(e: rlp::DecoderError) -> Self {
|
|
Error::RlpDecoderError(e)
|
|
}
|
|
}
|
|
|
|
impl From<ssz_types::Error> for Error {
|
|
fn from(e: ssz_types::Error) -> Self {
|
|
Error::SszError(e)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, IntoStaticStr)]
|
|
#[strum(serialize_all = "snake_case")]
|
|
pub enum PayloadStatusV1Status {
|
|
Valid,
|
|
Invalid,
|
|
Syncing,
|
|
Accepted,
|
|
InvalidBlockHash,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct PayloadStatusV1 {
|
|
pub status: PayloadStatusV1Status,
|
|
pub latest_valid_hash: Option<ExecutionBlockHash>,
|
|
pub validation_error: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
|
#[serde(untagged)]
|
|
pub enum BlockByNumberQuery<'a> {
|
|
Tag(&'a str),
|
|
}
|
|
|
|
/// Representation of an exection block with enough detail to determine the terminal PoW block.
|
|
///
|
|
/// See `get_pow_block_hash_at_total_difficulty`.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecutionBlock {
|
|
#[serde(rename = "hash")]
|
|
pub block_hash: ExecutionBlockHash,
|
|
#[serde(rename = "number", with = "serde_utils::u64_hex_be")]
|
|
pub block_number: u64,
|
|
pub parent_hash: ExecutionBlockHash,
|
|
pub total_difficulty: Uint256,
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub timestamp: u64,
|
|
}
|
|
|
|
/// Representation of an execution block with enough detail to reconstruct a payload.
|
|
#[superstruct(
|
|
variants(Bellatrix, Capella, Deneb, Electra),
|
|
variant_attributes(
|
|
derive(Clone, Debug, PartialEq, Serialize, Deserialize,),
|
|
serde(bound = "E: EthSpec", rename_all = "camelCase"),
|
|
),
|
|
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
|
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
|
)]
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(bound = "E: EthSpec", rename_all = "camelCase", untagged)]
|
|
pub struct ExecutionBlockWithTransactions<E: EthSpec> {
|
|
pub parent_hash: ExecutionBlockHash,
|
|
#[serde(alias = "miner")]
|
|
pub fee_recipient: Address,
|
|
pub state_root: Hash256,
|
|
pub receipts_root: Hash256,
|
|
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
|
|
pub logs_bloom: FixedVector<u8, E::BytesPerLogsBloom>,
|
|
#[serde(alias = "mixHash")]
|
|
pub prev_randao: Hash256,
|
|
#[serde(rename = "number", with = "serde_utils::u64_hex_be")]
|
|
pub block_number: u64,
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub gas_limit: u64,
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub gas_used: u64,
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub timestamp: u64,
|
|
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
|
|
pub extra_data: VariableList<u8, E::MaxExtraDataBytes>,
|
|
pub base_fee_per_gas: Uint256,
|
|
#[serde(rename = "hash")]
|
|
pub block_hash: ExecutionBlockHash,
|
|
pub transactions: Vec<Transaction>,
|
|
#[superstruct(only(Capella, Deneb, Electra))]
|
|
pub withdrawals: Vec<JsonWithdrawal>,
|
|
#[superstruct(only(Deneb, Electra))]
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub blob_gas_used: u64,
|
|
#[superstruct(only(Deneb, Electra))]
|
|
#[serde(with = "serde_utils::u64_hex_be")]
|
|
pub excess_blob_gas: u64,
|
|
#[superstruct(only(Electra))]
|
|
pub deposit_requests: Vec<JsonDepositRequest>,
|
|
#[superstruct(only(Electra))]
|
|
pub withdrawal_requests: Vec<JsonWithdrawalRequest>,
|
|
}
|
|
|
|
impl<E: EthSpec> TryFrom<ExecutionPayload<E>> for ExecutionBlockWithTransactions<E> {
|
|
type Error = Error;
|
|
|
|
fn try_from(payload: ExecutionPayload<E>) -> Result<Self, Error> {
|
|
let json_payload = match payload {
|
|
ExecutionPayload::Bellatrix(block) => {
|
|
Self::Bellatrix(ExecutionBlockWithTransactionsBellatrix {
|
|
parent_hash: block.parent_hash,
|
|
fee_recipient: block.fee_recipient,
|
|
state_root: block.state_root,
|
|
receipts_root: block.receipts_root,
|
|
logs_bloom: block.logs_bloom,
|
|
prev_randao: block.prev_randao,
|
|
block_number: block.block_number,
|
|
gas_limit: block.gas_limit,
|
|
gas_used: block.gas_used,
|
|
timestamp: block.timestamp,
|
|
extra_data: block.extra_data,
|
|
base_fee_per_gas: block.base_fee_per_gas,
|
|
block_hash: block.block_hash,
|
|
transactions: block
|
|
.transactions
|
|
.iter()
|
|
.map(|tx| Transaction::decode(&Rlp::new(tx)))
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
})
|
|
}
|
|
ExecutionPayload::Capella(block) => {
|
|
Self::Capella(ExecutionBlockWithTransactionsCapella {
|
|
parent_hash: block.parent_hash,
|
|
fee_recipient: block.fee_recipient,
|
|
state_root: block.state_root,
|
|
receipts_root: block.receipts_root,
|
|
logs_bloom: block.logs_bloom,
|
|
prev_randao: block.prev_randao,
|
|
block_number: block.block_number,
|
|
gas_limit: block.gas_limit,
|
|
gas_used: block.gas_used,
|
|
timestamp: block.timestamp,
|
|
extra_data: block.extra_data,
|
|
base_fee_per_gas: block.base_fee_per_gas,
|
|
block_hash: block.block_hash,
|
|
transactions: block
|
|
.transactions
|
|
.iter()
|
|
.map(|tx| Transaction::decode(&Rlp::new(tx)))
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
withdrawals: Vec::from(block.withdrawals)
|
|
.into_iter()
|
|
.map(|withdrawal| withdrawal.into())
|
|
.collect(),
|
|
})
|
|
}
|
|
ExecutionPayload::Deneb(block) => Self::Deneb(ExecutionBlockWithTransactionsDeneb {
|
|
parent_hash: block.parent_hash,
|
|
fee_recipient: block.fee_recipient,
|
|
state_root: block.state_root,
|
|
receipts_root: block.receipts_root,
|
|
logs_bloom: block.logs_bloom,
|
|
prev_randao: block.prev_randao,
|
|
block_number: block.block_number,
|
|
gas_limit: block.gas_limit,
|
|
gas_used: block.gas_used,
|
|
timestamp: block.timestamp,
|
|
extra_data: block.extra_data,
|
|
base_fee_per_gas: block.base_fee_per_gas,
|
|
block_hash: block.block_hash,
|
|
transactions: block
|
|
.transactions
|
|
.iter()
|
|
.map(|tx| Transaction::decode(&Rlp::new(tx)))
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
withdrawals: Vec::from(block.withdrawals)
|
|
.into_iter()
|
|
.map(|withdrawal| withdrawal.into())
|
|
.collect(),
|
|
blob_gas_used: block.blob_gas_used,
|
|
excess_blob_gas: block.excess_blob_gas,
|
|
}),
|
|
ExecutionPayload::Electra(block) => {
|
|
Self::Electra(ExecutionBlockWithTransactionsElectra {
|
|
parent_hash: block.parent_hash,
|
|
fee_recipient: block.fee_recipient,
|
|
state_root: block.state_root,
|
|
receipts_root: block.receipts_root,
|
|
logs_bloom: block.logs_bloom,
|
|
prev_randao: block.prev_randao,
|
|
block_number: block.block_number,
|
|
gas_limit: block.gas_limit,
|
|
gas_used: block.gas_used,
|
|
timestamp: block.timestamp,
|
|
extra_data: block.extra_data,
|
|
base_fee_per_gas: block.base_fee_per_gas,
|
|
block_hash: block.block_hash,
|
|
transactions: block
|
|
.transactions
|
|
.iter()
|
|
.map(|tx| Transaction::decode(&Rlp::new(tx)))
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
withdrawals: Vec::from(block.withdrawals)
|
|
.into_iter()
|
|
.map(|withdrawal| withdrawal.into())
|
|
.collect(),
|
|
blob_gas_used: block.blob_gas_used,
|
|
excess_blob_gas: block.excess_blob_gas,
|
|
deposit_requests: block
|
|
.deposit_requests
|
|
.into_iter()
|
|
.map(|deposit| deposit.into())
|
|
.collect(),
|
|
withdrawal_requests: block
|
|
.withdrawal_requests
|
|
.into_iter()
|
|
.map(|withdrawal| withdrawal.into())
|
|
.collect(),
|
|
})
|
|
}
|
|
};
|
|
Ok(json_payload)
|
|
}
|
|
}
|
|
|
|
#[superstruct(
|
|
variants(V1, V2, V3),
|
|
variant_attributes(derive(Clone, Debug, Eq, Hash, PartialEq),),
|
|
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
|
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
|
)]
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
pub struct PayloadAttributes {
|
|
#[superstruct(getter(copy))]
|
|
pub timestamp: u64,
|
|
#[superstruct(getter(copy))]
|
|
pub prev_randao: Hash256,
|
|
#[superstruct(getter(copy))]
|
|
pub suggested_fee_recipient: Address,
|
|
#[superstruct(only(V2, V3))]
|
|
pub withdrawals: Vec<Withdrawal>,
|
|
#[superstruct(only(V3), partial_getter(copy))]
|
|
pub parent_beacon_block_root: Hash256,
|
|
}
|
|
|
|
impl PayloadAttributes {
|
|
pub fn new(
|
|
timestamp: u64,
|
|
prev_randao: Hash256,
|
|
suggested_fee_recipient: Address,
|
|
withdrawals: Option<Vec<Withdrawal>>,
|
|
parent_beacon_block_root: Option<Hash256>,
|
|
) -> Self {
|
|
match withdrawals {
|
|
Some(withdrawals) => match parent_beacon_block_root {
|
|
Some(parent_beacon_block_root) => PayloadAttributes::V3(PayloadAttributesV3 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
parent_beacon_block_root,
|
|
}),
|
|
None => PayloadAttributes::V2(PayloadAttributesV2 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
}),
|
|
},
|
|
None => PayloadAttributes::V1(PayloadAttributesV1 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<PayloadAttributes> for SsePayloadAttributes {
|
|
fn from(pa: PayloadAttributes) -> Self {
|
|
match pa {
|
|
PayloadAttributes::V1(PayloadAttributesV1 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
}) => Self::V1(SsePayloadAttributesV1 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
}),
|
|
PayloadAttributes::V2(PayloadAttributesV2 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
}) => Self::V2(SsePayloadAttributesV2 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
}),
|
|
PayloadAttributes::V3(PayloadAttributesV3 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
parent_beacon_block_root,
|
|
}) => Self::V3(SsePayloadAttributesV3 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
withdrawals,
|
|
parent_beacon_block_root,
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct ForkchoiceUpdatedResponse {
|
|
pub payload_status: PayloadStatusV1,
|
|
pub payload_id: Option<PayloadId>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub enum ProposeBlindedBlockResponseStatus {
|
|
Valid,
|
|
Invalid,
|
|
Syncing,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct ProposeBlindedBlockResponse {
|
|
pub status: ProposeBlindedBlockResponseStatus,
|
|
pub latest_valid_hash: Option<Hash256>,
|
|
pub validation_error: Option<String>,
|
|
}
|
|
|
|
#[superstruct(
|
|
variants(Bellatrix, Capella, Deneb, Electra),
|
|
variant_attributes(derive(Clone, Debug, PartialEq),),
|
|
map_into(ExecutionPayload),
|
|
map_ref_into(ExecutionPayloadRef),
|
|
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
|
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
|
)]
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct GetPayloadResponse<E: EthSpec> {
|
|
#[superstruct(
|
|
only(Bellatrix),
|
|
partial_getter(rename = "execution_payload_bellatrix")
|
|
)]
|
|
pub execution_payload: ExecutionPayloadBellatrix<E>,
|
|
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
|
pub execution_payload: ExecutionPayloadCapella<E>,
|
|
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
|
|
pub execution_payload: ExecutionPayloadDeneb<E>,
|
|
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
|
pub execution_payload: ExecutionPayloadElectra<E>,
|
|
pub block_value: Uint256,
|
|
#[superstruct(only(Deneb, Electra))]
|
|
pub blobs_bundle: BlobsBundle<E>,
|
|
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
|
pub should_override_builder: bool,
|
|
}
|
|
|
|
impl<E: EthSpec> GetPayloadResponse<E> {
|
|
pub fn fee_recipient(&self) -> Address {
|
|
ExecutionPayloadRef::from(self.to_ref()).fee_recipient()
|
|
}
|
|
|
|
pub fn block_hash(&self) -> ExecutionBlockHash {
|
|
ExecutionPayloadRef::from(self.to_ref()).block_hash()
|
|
}
|
|
|
|
pub fn block_number(&self) -> u64 {
|
|
ExecutionPayloadRef::from(self.to_ref()).block_number()
|
|
}
|
|
}
|
|
|
|
impl<'a, E: EthSpec> From<GetPayloadResponseRef<'a, E>> for ExecutionPayloadRef<'a, E> {
|
|
fn from(response: GetPayloadResponseRef<'a, E>) -> Self {
|
|
map_get_payload_response_ref_into_execution_payload_ref!(&'a _, response, |inner, cons| {
|
|
cons(&inner.execution_payload)
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<E: EthSpec> From<GetPayloadResponse<E>> for ExecutionPayload<E> {
|
|
fn from(response: GetPayloadResponse<E>) -> Self {
|
|
map_get_payload_response_into_execution_payload!(response, |inner, cons| {
|
|
cons(inner.execution_payload)
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<E: EthSpec> From<GetPayloadResponse<E>>
|
|
for (ExecutionPayload<E>, Uint256, Option<BlobsBundle<E>>)
|
|
{
|
|
fn from(response: GetPayloadResponse<E>) -> Self {
|
|
match response {
|
|
GetPayloadResponse::Bellatrix(inner) => (
|
|
ExecutionPayload::Bellatrix(inner.execution_payload),
|
|
inner.block_value,
|
|
None,
|
|
),
|
|
GetPayloadResponse::Capella(inner) => (
|
|
ExecutionPayload::Capella(inner.execution_payload),
|
|
inner.block_value,
|
|
None,
|
|
),
|
|
GetPayloadResponse::Deneb(inner) => (
|
|
ExecutionPayload::Deneb(inner.execution_payload),
|
|
inner.block_value,
|
|
Some(inner.blobs_bundle),
|
|
),
|
|
GetPayloadResponse::Electra(inner) => (
|
|
ExecutionPayload::Electra(inner.execution_payload),
|
|
inner.block_value,
|
|
Some(inner.blobs_bundle),
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum GetPayloadResponseType<E: EthSpec> {
|
|
Full(GetPayloadResponse<E>),
|
|
Blinded(GetPayloadResponse<E>),
|
|
}
|
|
|
|
impl<E: EthSpec> GetPayloadResponse<E> {
|
|
pub fn execution_payload_ref(&self) -> ExecutionPayloadRef<E> {
|
|
self.to_ref().into()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct ExecutionPayloadBodyV1<E: EthSpec> {
|
|
pub transactions: Transactions<E>,
|
|
pub withdrawals: Option<Withdrawals<E>>,
|
|
pub deposit_requests: Option<DepositRequests<E>>,
|
|
pub withdrawal_requests: Option<WithdrawalRequests<E>>,
|
|
}
|
|
|
|
impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
|
|
pub fn to_payload(
|
|
self,
|
|
header: ExecutionPayloadHeader<E>,
|
|
) -> Result<ExecutionPayload<E>, String> {
|
|
match header {
|
|
ExecutionPayloadHeader::Bellatrix(header) => {
|
|
if self.withdrawals.is_some() {
|
|
return Err(format!(
|
|
"block {} is merge but payload body has withdrawals",
|
|
header.block_hash
|
|
));
|
|
}
|
|
Ok(ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix {
|
|
parent_hash: header.parent_hash,
|
|
fee_recipient: header.fee_recipient,
|
|
state_root: header.state_root,
|
|
receipts_root: header.receipts_root,
|
|
logs_bloom: header.logs_bloom,
|
|
prev_randao: header.prev_randao,
|
|
block_number: header.block_number,
|
|
gas_limit: header.gas_limit,
|
|
gas_used: header.gas_used,
|
|
timestamp: header.timestamp,
|
|
extra_data: header.extra_data,
|
|
base_fee_per_gas: header.base_fee_per_gas,
|
|
block_hash: header.block_hash,
|
|
transactions: self.transactions,
|
|
}))
|
|
}
|
|
ExecutionPayloadHeader::Capella(header) => {
|
|
if let Some(withdrawals) = self.withdrawals {
|
|
Ok(ExecutionPayload::Capella(ExecutionPayloadCapella {
|
|
parent_hash: header.parent_hash,
|
|
fee_recipient: header.fee_recipient,
|
|
state_root: header.state_root,
|
|
receipts_root: header.receipts_root,
|
|
logs_bloom: header.logs_bloom,
|
|
prev_randao: header.prev_randao,
|
|
block_number: header.block_number,
|
|
gas_limit: header.gas_limit,
|
|
gas_used: header.gas_used,
|
|
timestamp: header.timestamp,
|
|
extra_data: header.extra_data,
|
|
base_fee_per_gas: header.base_fee_per_gas,
|
|
block_hash: header.block_hash,
|
|
transactions: self.transactions,
|
|
withdrawals,
|
|
}))
|
|
} else {
|
|
Err(format!(
|
|
"block {} is capella but payload body doesn't have withdrawals",
|
|
header.block_hash
|
|
))
|
|
}
|
|
}
|
|
ExecutionPayloadHeader::Deneb(header) => {
|
|
if let Some(withdrawals) = self.withdrawals {
|
|
Ok(ExecutionPayload::Deneb(ExecutionPayloadDeneb {
|
|
parent_hash: header.parent_hash,
|
|
fee_recipient: header.fee_recipient,
|
|
state_root: header.state_root,
|
|
receipts_root: header.receipts_root,
|
|
logs_bloom: header.logs_bloom,
|
|
prev_randao: header.prev_randao,
|
|
block_number: header.block_number,
|
|
gas_limit: header.gas_limit,
|
|
gas_used: header.gas_used,
|
|
timestamp: header.timestamp,
|
|
extra_data: header.extra_data,
|
|
base_fee_per_gas: header.base_fee_per_gas,
|
|
block_hash: header.block_hash,
|
|
transactions: self.transactions,
|
|
withdrawals,
|
|
blob_gas_used: header.blob_gas_used,
|
|
excess_blob_gas: header.excess_blob_gas,
|
|
}))
|
|
} else {
|
|
Err(format!(
|
|
"block {} is post-capella but payload body doesn't have withdrawals",
|
|
header.block_hash
|
|
))
|
|
}
|
|
}
|
|
ExecutionPayloadHeader::Electra(header) => {
|
|
let withdrawals_exist = self.withdrawals.is_some();
|
|
let deposit_requests_exist = self.deposit_requests.is_some();
|
|
let withdrawal_requests_exist = self.withdrawal_requests.is_some();
|
|
if let (Some(withdrawals), Some(deposit_requests), Some(withdrawal_requests)) = (
|
|
self.withdrawals,
|
|
self.deposit_requests,
|
|
self.withdrawal_requests,
|
|
) {
|
|
Ok(ExecutionPayload::Electra(ExecutionPayloadElectra {
|
|
parent_hash: header.parent_hash,
|
|
fee_recipient: header.fee_recipient,
|
|
state_root: header.state_root,
|
|
receipts_root: header.receipts_root,
|
|
logs_bloom: header.logs_bloom,
|
|
prev_randao: header.prev_randao,
|
|
block_number: header.block_number,
|
|
gas_limit: header.gas_limit,
|
|
gas_used: header.gas_used,
|
|
timestamp: header.timestamp,
|
|
extra_data: header.extra_data,
|
|
base_fee_per_gas: header.base_fee_per_gas,
|
|
block_hash: header.block_hash,
|
|
transactions: self.transactions,
|
|
withdrawals,
|
|
blob_gas_used: header.blob_gas_used,
|
|
excess_blob_gas: header.excess_blob_gas,
|
|
deposit_requests,
|
|
withdrawal_requests,
|
|
}))
|
|
} else {
|
|
Err(format!(
|
|
"block {} is post-electra but payload body doesn't have withdrawals/deposit_requests/withdrawal_requests \
|
|
withdrawals: {}, deposit_requests: {}, withdrawal_requests: {}",
|
|
header.block_hash, withdrawals_exist, deposit_requests_exist, withdrawal_requests_exist
|
|
))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct EngineCapabilities {
|
|
pub new_payload_v1: bool,
|
|
pub new_payload_v2: bool,
|
|
pub new_payload_v3: bool,
|
|
pub new_payload_v4: bool,
|
|
pub forkchoice_updated_v1: bool,
|
|
pub forkchoice_updated_v2: bool,
|
|
pub forkchoice_updated_v3: bool,
|
|
pub get_payload_bodies_by_hash_v1: bool,
|
|
pub get_payload_bodies_by_range_v1: bool,
|
|
pub get_payload_v1: bool,
|
|
pub get_payload_v2: bool,
|
|
pub get_payload_v3: bool,
|
|
pub get_payload_v4: bool,
|
|
pub get_client_version_v1: bool,
|
|
}
|
|
|
|
impl EngineCapabilities {
|
|
pub fn to_response(&self) -> Vec<&str> {
|
|
let mut response = Vec::new();
|
|
if self.new_payload_v1 {
|
|
response.push(ENGINE_NEW_PAYLOAD_V1);
|
|
}
|
|
if self.new_payload_v2 {
|
|
response.push(ENGINE_NEW_PAYLOAD_V2);
|
|
}
|
|
if self.new_payload_v3 {
|
|
response.push(ENGINE_NEW_PAYLOAD_V3);
|
|
}
|
|
if self.new_payload_v4 {
|
|
response.push(ENGINE_NEW_PAYLOAD_V4);
|
|
}
|
|
if self.forkchoice_updated_v1 {
|
|
response.push(ENGINE_FORKCHOICE_UPDATED_V1);
|
|
}
|
|
if self.forkchoice_updated_v2 {
|
|
response.push(ENGINE_FORKCHOICE_UPDATED_V2);
|
|
}
|
|
if self.forkchoice_updated_v3 {
|
|
response.push(ENGINE_FORKCHOICE_UPDATED_V3);
|
|
}
|
|
if self.get_payload_bodies_by_hash_v1 {
|
|
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1);
|
|
}
|
|
if self.get_payload_bodies_by_range_v1 {
|
|
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1);
|
|
}
|
|
if self.get_payload_v1 {
|
|
response.push(ENGINE_GET_PAYLOAD_V1);
|
|
}
|
|
if self.get_payload_v2 {
|
|
response.push(ENGINE_GET_PAYLOAD_V2);
|
|
}
|
|
if self.get_payload_v3 {
|
|
response.push(ENGINE_GET_PAYLOAD_V3);
|
|
}
|
|
if self.get_payload_v4 {
|
|
response.push(ENGINE_GET_PAYLOAD_V4);
|
|
}
|
|
if self.get_client_version_v1 {
|
|
response.push(ENGINE_GET_CLIENT_VERSION_V1);
|
|
}
|
|
|
|
response
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum ClientCode {
|
|
Besu,
|
|
EtherumJS,
|
|
Erigon,
|
|
GoEthereum,
|
|
Grandine,
|
|
Lighthouse,
|
|
Lodestar,
|
|
Nethermind,
|
|
Nimbus,
|
|
Teku,
|
|
Prysm,
|
|
Reth,
|
|
Unknown(String),
|
|
}
|
|
|
|
impl std::fmt::Display for ClientCode {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let s = match self {
|
|
ClientCode::Besu => "BU",
|
|
ClientCode::EtherumJS => "EJ",
|
|
ClientCode::Erigon => "EG",
|
|
ClientCode::GoEthereum => "GE",
|
|
ClientCode::Grandine => "GR",
|
|
ClientCode::Lighthouse => "LH",
|
|
ClientCode::Lodestar => "LS",
|
|
ClientCode::Nethermind => "NM",
|
|
ClientCode::Nimbus => "NB",
|
|
ClientCode::Teku => "TK",
|
|
ClientCode::Prysm => "PM",
|
|
ClientCode::Reth => "RH",
|
|
ClientCode::Unknown(code) => code,
|
|
};
|
|
write!(f, "{}", s)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<String> for ClientCode {
|
|
type Error = String;
|
|
|
|
fn try_from(code: String) -> Result<Self, Self::Error> {
|
|
match code.as_str() {
|
|
"BU" => Ok(Self::Besu),
|
|
"EJ" => Ok(Self::EtherumJS),
|
|
"EG" => Ok(Self::Erigon),
|
|
"GE" => Ok(Self::GoEthereum),
|
|
"GR" => Ok(Self::Grandine),
|
|
"LH" => Ok(Self::Lighthouse),
|
|
"LS" => Ok(Self::Lodestar),
|
|
"NM" => Ok(Self::Nethermind),
|
|
"NB" => Ok(Self::Nimbus),
|
|
"TK" => Ok(Self::Teku),
|
|
"PM" => Ok(Self::Prysm),
|
|
"RH" => Ok(Self::Reth),
|
|
string => {
|
|
if string.len() == 2 {
|
|
Ok(Self::Unknown(code))
|
|
} else {
|
|
Err(format!("Invalid client code: {}", code))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct CommitPrefix(pub String);
|
|
|
|
impl TryFrom<String> for CommitPrefix {
|
|
type Error = String;
|
|
|
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
|
// Check if the input starts with '0x' and strip it if it does
|
|
let commit_prefix = value.strip_prefix("0x").unwrap_or(&value);
|
|
|
|
// Ensure length is exactly 8 characters after '0x' removal
|
|
if commit_prefix.len() != 8 {
|
|
return Err(
|
|
"Input must be exactly 8 characters long (excluding any '0x' prefix)".to_string(),
|
|
);
|
|
}
|
|
|
|
// Ensure all characters are valid hex digits
|
|
if commit_prefix.chars().all(|c| c.is_ascii_hexdigit()) {
|
|
Ok(CommitPrefix(commit_prefix.to_lowercase()))
|
|
} else {
|
|
Err("Input must contain only hexadecimal characters".to_string())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for CommitPrefix {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct ClientVersionV1 {
|
|
pub code: ClientCode,
|
|
pub name: String,
|
|
pub version: String,
|
|
pub commit: CommitPrefix,
|
|
}
|
|
|
|
impl ClientVersionV1 {
|
|
pub fn calculate_graffiti(&self, lighthouse_commit_prefix: CommitPrefix) -> Graffiti {
|
|
let graffiti_string = format!(
|
|
"{}{}LH{}",
|
|
self.code,
|
|
self.commit
|
|
.0
|
|
.get(..4)
|
|
.map_or_else(|| self.commit.0.as_str(), |s| s)
|
|
.to_lowercase(),
|
|
lighthouse_commit_prefix
|
|
.0
|
|
.get(..4)
|
|
.unwrap_or("0000")
|
|
.to_lowercase(),
|
|
);
|
|
let mut graffiti_bytes = [0u8; GRAFFITI_BYTES_LEN];
|
|
let bytes_to_copy = std::cmp::min(graffiti_string.len(), GRAFFITI_BYTES_LEN);
|
|
graffiti_bytes[..bytes_to_copy]
|
|
.copy_from_slice(&graffiti_string.as_bytes()[..bytes_to_copy]);
|
|
|
|
Graffiti::from(graffiti_bytes)
|
|
}
|
|
}
|