Skip to content

Commit

Permalink
feat: implement Capella upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
mempirate committed Apr 16, 2023
1 parent 0dc938e commit dd1b5fd
Show file tree
Hide file tree
Showing 13 changed files with 389 additions and 197 deletions.
434 changes: 292 additions & 142 deletions Cargo.lock

Large diffs are not rendered by default.

33 changes: 17 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ edition = "2021"
[dependencies]
discv5 = { version = "0.1.0", features = ["libp2p"] }
unsigned-varint = { version = "0.6.0", features = ["codec"] }
types = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_ssz_types = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
types = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_ssz_types = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
serde = { version = "1.0.116", features = ["derive"] }
serde_derive = "1"
eth2_ssz = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_ssz_derive = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_ssz = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_ssz_derive = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
slog = { version = "2.5.2", features = ["max_level_trace"] }
lighthouse_version = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
lighthouse_version = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
tokio = { version = "1.14.0", features = ["time", "macros"] }
tokio-stream = "0.1"
futures = "0.3.7"
futures = "0.3.28"
error-chain = "0.12.4"
dirs = "3.0.1"
fnv = "1.0.7"
lazy_static = "1.4.0"
lighthouse_metrics = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
lighthouse_metrics = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
smallvec = "1.6.1"
tokio-io-timeout = "1.1.1"
lru = "0.7.1"
Expand All @@ -34,14 +34,14 @@ snap = "1.0.1"
hex = "0.4.2"
tokio-util = { version = "0.6.2", features = ["codec", "compat", "time"] }
tiny-keccak = "2.0.2"
task_executor = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
task_executor = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
rand = "0.8.5"
directory = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
directory = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
regex = "1.5.5"
strum = { version = "0.24.0", features = ["derive"] }
superstruct = "0.5.0"
prometheus-client = "0.18.0"
unused_port = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
unused_port = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
delay_map = "0.1.1"
tracing = { version = "0.1" }
tracing-subscriber = { version = "0.2", features = ["fmt", "env-filter"] }
Expand All @@ -64,13 +64,14 @@ features = [

# Some lighthouse patches
[patch.crates-io]
eth2_ssz = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_ssz_types = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_serde_utils = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_hashing = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
eth2_ssz = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_ssz_types = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_ssz_derive = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_serde_utils = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
eth2_hashing = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }

tree_hash = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
tree_hash_derive = { git = "https://github.com/sigp/lighthouse", tag = "v3.3.0" }
tree_hash = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }
tree_hash_derive = { git = "https://github.com/sigp/lighthouse", tag = "v4.0.1" }

[dev-dependencies]
slog-term = "2.6.0"
Expand Down
4 changes: 2 additions & 2 deletions examples/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ async fn main() {
.message()
.execution_payload()
.unwrap()
.execution_payload
.block_number;
.execution_payload_ref()
.block_number();

println!(
"Received block {} (source peer: {:?}",
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ pub fn gossipsub_config(network_load: u8, fork_context: Arc<ForkContext>) -> Gos
match fork_context.current_fork() {
// according to: https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#the-gossip-domain-gossipsub
// the derivation of the message-id remains the same in the merge
ForkName::Altair | ForkName::Merge => {
ForkName::Altair | ForkName::Merge | ForkName::Capella => {
let topic_len_bytes = topic_bytes.len().to_le_bytes();
let mut vec = Vec::with_capacity(
prefix.len() + topic_len_bytes.len() + topic_bytes.len() + message.data.len(),
Expand Down
4 changes: 2 additions & 2 deletions src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,14 +1062,14 @@ mod tests {
use crate::rpc::methods::{MetaData, MetaDataV2};
use enr::EnrBuilder;
use types::{BitVector, MinimalEthSpec, SubnetId};
use unused_port::unused_udp_port;
use unused_port::unused_udp4_port;

type E = MinimalEthSpec;

async fn build_discovery() -> Discovery<E> {
let keypair = libp2p::identity::Keypair::generate_secp256k1();
let config = NetworkConfig {
discovery_port: unused_udp_port().unwrap(),
discovery_port: unused_udp4_port().unwrap(),
..Default::default()
};
let enr_key: CombinedKey = CombinedKey::from_libp2p(&keypair).unwrap();
Expand Down
8 changes: 0 additions & 8 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,3 @@ pub fn check_nat() {
inc_counter(&NAT_OPEN);
}
}

pub fn scrape_discovery_metrics() {
let metrics = discv5::metrics::Metrics::from(discv5::Discv5::raw_metrics());
set_float_gauge(&DISCOVERY_REQS, metrics.unsolicited_requests_per_second);
set_gauge(&DISCOVERY_SESSIONS, metrics.active_sessions as i64);
set_gauge(&DISCOVERY_SENT_BYTES, metrics.bytes_sent as i64);
set_gauge(&DISCOVERY_RECV_BYTES, metrics.bytes_recv as i64);
}
4 changes: 2 additions & 2 deletions src/network/gossipsub_scoring_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ impl<TSpec: EthSpec> PeerScoreSettings<TSpec> {

let modulo_smaller = max(
1,
smaller_committee_size / self.target_aggregators_per_committee as usize,
smaller_committee_size / self.target_aggregators_per_committee,
);
let modulo_larger = max(
1,
(smaller_committee_size + 1) / self.target_aggregators_per_committee as usize,
(smaller_committee_size + 1) / self.target_aggregators_per_committee,
);

Ok((
Expand Down
2 changes: 1 addition & 1 deletion src/network/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn keypair_from_hex(hex_bytes: &str) -> error::Result<Keypair> {
hex_bytes.to_string()
};

hex::decode(&hex_bytes)
hex::decode(hex_bytes)
.map_err(|e| format!("Failed to parse p2p secret key bytes: {:?}", e).into())
.and_then(keypair_from_bytes)
}
Expand Down
3 changes: 3 additions & 0 deletions src/rpc/codec/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,17 @@ mod tests {
let mut chain_spec = Spec::default_spec();
let altair_fork_epoch = Epoch::new(1);
let merge_fork_epoch = Epoch::new(2);
let capella_fork_epoch = Epoch::new(3);

chain_spec.altair_fork_epoch = Some(altair_fork_epoch);
chain_spec.bellatrix_fork_epoch = Some(merge_fork_epoch);
chain_spec.capella_fork_epoch = Some(capella_fork_epoch);

let current_slot = match fork_name {
ForkName::Base => Slot::new(0),
ForkName::Altair => altair_fork_epoch.start_slot(Spec::slots_per_epoch()),
ForkName::Merge => merge_fork_epoch.start_slot(Spec::slots_per_epoch()),
ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()),
};
ForkContext::new::<Spec>(current_slot, Hash256::zero(), &chain_spec)
}
Expand Down
27 changes: 22 additions & 5 deletions src/rpc/codec/ssz_snappy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::sync::Arc;
use tokio_util::codec::{Decoder, Encoder};
use types::{
EthSpec, ForkContext, ForkName, SignedBeaconBlock, SignedBeaconBlockAltair,
SignedBeaconBlockBase, SignedBeaconBlockMerge,
SignedBeaconBlockBase, SignedBeaconBlockCapella, SignedBeaconBlockMerge,
};
use unsigned_varint::codec::Uvi;

Expand Down Expand Up @@ -407,6 +407,10 @@ fn context_bytes<T: EthSpec>(
return match **ref_box_block {
// NOTE: If you are adding another fork type here, be sure to modify the
// `fork_context.to_context_bytes()` function to support it as well!
SignedBeaconBlock::Capella { .. } => {
// Capella context being `None` implies that "merge never happened".
fork_context.to_context_bytes(ForkName::Capella)
}
SignedBeaconBlock::Merge { .. } => {
// Merge context being `None` implies that "merge never happened".
fork_context.to_context_bytes(ForkName::Merge)
Expand Down Expand Up @@ -441,7 +445,7 @@ fn handle_length(
// Note: length-prefix of > 10 bytes(uint64) would be a decoding error
match uvi_codec.decode(bytes).map_err(RPCError::from)? {
Some(length) => {
*len = Some(length as usize);
*len = Some(length);
Ok(Some(length))
}
None => Ok(None), // need more bytes to decode length
Expand Down Expand Up @@ -586,6 +590,11 @@ fn handle_v2_response<T: EthSpec>(
decoded_buffer,
)?),
)))),
ForkName::Capella => Ok(Some(RPCResponse::BlocksByRange(Arc::new(
SignedBeaconBlock::Capella(SignedBeaconBlockCapella::from_ssz_bytes(
decoded_buffer,
)?),
)))),
},
Protocol::BlocksByRoot => match fork_name {
ForkName::Altair => Ok(Some(RPCResponse::BlocksByRoot(Arc::new(
Expand All @@ -601,6 +610,11 @@ fn handle_v2_response<T: EthSpec>(
decoded_buffer,
)?),
)))),
ForkName::Capella => Ok(Some(RPCResponse::BlocksByRoot(Arc::new(
SignedBeaconBlock::Capella(SignedBeaconBlockCapella::from_ssz_bytes(
decoded_buffer,
)?),
)))),
},
_ => Err(RPCError::ErrorResponse(
RPCResponseErrorCode::InvalidRequest,
Expand All @@ -625,9 +639,9 @@ fn context_bytes_to_fork_name(
)
})
}

#[cfg(test)]
mod tests {

use super::*;
use crate::rpc::{protocol::*, MetaData};
use crate::{
Expand All @@ -636,8 +650,8 @@ mod tests {
};
use std::sync::Arc;
use types::{
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, Epoch, ForkContext,
FullPayload, Hash256, Signature, SignedBeaconBlock, Slot,
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, EmptyBlock, Epoch,
ForkContext, FullPayload, Hash256, Signature, SignedBeaconBlock, Slot,
};

use snap::write::FrameEncoder;
Expand All @@ -650,14 +664,17 @@ mod tests {
let mut chain_spec = Spec::default_spec();
let altair_fork_epoch = Epoch::new(1);
let merge_fork_epoch = Epoch::new(2);
let capella_fork_epoch = Epoch::new(3);

chain_spec.altair_fork_epoch = Some(altair_fork_epoch);
chain_spec.bellatrix_fork_epoch = Some(merge_fork_epoch);
chain_spec.capella_fork_epoch = Some(capella_fork_epoch);

let current_slot = match fork_name {
ForkName::Base => Slot::new(0),
ForkName::Altair => altair_fork_epoch.start_slot(Spec::slots_per_epoch()),
ForkName::Merge => merge_fork_epoch.start_slot(Spec::slots_per_epoch()),
ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()),
};
ForkContext::new::<Spec>(current_slot, Hash256::zero(), &chain_spec)
}
Expand Down
27 changes: 23 additions & 4 deletions src/rpc/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use tokio_util::{
compat::{Compat, FuturesAsyncReadCompatExt},
};
use types::{
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, EthSpec, ForkContext,
ForkName, Hash256, MainnetEthSpec, Signature, SignedBeaconBlock,
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockMerge,
EmptyBlock, EthSpec, ForkContext, ForkName, Hash256, MainnetEthSpec, Signature,
SignedBeaconBlock,
};

lazy_static! {
Expand Down Expand Up @@ -61,16 +62,28 @@ lazy_static! {
.as_ssz_bytes()
.len();

pub static ref SIGNED_BEACON_BLOCK_CAPELLA_MAX_WITHOUT_PAYLOAD: usize = SignedBeaconBlock::<MainnetEthSpec>::from_block(
BeaconBlock::Capella(BeaconBlockCapella::full(&MainnetEthSpec::default_spec())),
Signature::empty(),
)
.as_ssz_bytes()
.len();


/// The `BeaconBlockMerge` block has an `ExecutionPayload` field which has a max size ~16 GiB for future proofing.
/// We calculate the value from its fields instead of constructing the block and checking the length.
/// Note: This is only the theoretical upper bound. We further bound the max size we receive over the network
/// with `MAX_RPC_SIZE_POST_MERGE`.
pub static ref SIGNED_BEACON_BLOCK_MERGE_MAX: usize =
// Size of a full altair block
*SIGNED_BEACON_BLOCK_ALTAIR_MAX
+ types::ExecutionPayload::<MainnetEthSpec>::max_execution_payload_size() // adding max size of execution payload (~16gb)
+ types::ExecutionPayload::<MainnetEthSpec>::max_execution_payload_merge_size() // adding max size of execution payload (~16gb)
+ ssz::BYTES_PER_LENGTH_OFFSET; // Adding the additional ssz offset for the `ExecutionPayload` field

pub static ref SIGNED_BEACON_BLOCK_CAPELLA_MAX: usize = *SIGNED_BEACON_BLOCK_CAPELLA_MAX_WITHOUT_PAYLOAD
+ types::ExecutionPayload::<MainnetEthSpec>::max_execution_payload_capella_size() // adding max size of execution payload (~16gb)
+ ssz::BYTES_PER_LENGTH_OFFSET; // Adding the additional ssz offset for the `ExecutionPayload` field

pub static ref BLOCKS_BY_ROOT_REQUEST_MIN: usize =
VariableList::<Hash256, MaxRequestBlocks>::from(Vec::<Hash256>::new())
.as_ssz_bytes()
Expand Down Expand Up @@ -102,6 +115,7 @@ lazy_static! {
pub(crate) const MAX_RPC_SIZE: usize = 1_048_576; // 1M
/// The maximum bytes that can be sent across the RPC post-merge.
pub(crate) const MAX_RPC_SIZE_POST_MERGE: usize = 10 * 1_048_576; // 10M
pub(crate) const MAX_RPC_SIZE_POST_CAPELLA: usize = 10 * 1_048_576; // 10M
/// The protocol prefix the RPC protocol id.
const PROTOCOL_PREFIX: &str = "/eth2/beacon_chain/req";
/// Time allowed for the first byte of a request to arrive before we time out (Time To First Byte).
Expand All @@ -113,8 +127,9 @@ const REQUEST_TIMEOUT: u64 = 15;
/// Returns the maximum bytes that can be sent across the RPC.
pub fn max_rpc_size(fork_context: &ForkContext) -> usize {
match fork_context.current_fork() {
ForkName::Merge => MAX_RPC_SIZE_POST_MERGE,
ForkName::Altair | ForkName::Base => MAX_RPC_SIZE,
ForkName::Merge => MAX_RPC_SIZE_POST_MERGE,
ForkName::Capella => MAX_RPC_SIZE_POST_CAPELLA,
}
}

Expand All @@ -135,6 +150,10 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits {
*SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and merge blocks
*SIGNED_BEACON_BLOCK_MERGE_MAX, // Merge block is larger than base and altair blocks
),
ForkName::Capella => RpcLimits::new(
*SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and merge blocks
*SIGNED_BEACON_BLOCK_CAPELLA_MAX, // Capella block is larger than base, altair and merge blocks
),
}
}

Expand Down
30 changes: 18 additions & 12 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,17 @@ impl Service {
discovery_port: self.cfg.discovery_port,
boot_nodes_enr: self.cfg.boot_enrs,
target_peers: self.cfg.max_peers,
network_load: 5,
..Default::default()
};

// Specify the fork
let fork = ForkName::Merge;
let fork = ForkName::Capella;

// Populate the chain spec
let mainnet_spec = ChainSpec::mainnet();

// Get the merge slot
let merge_slot = mainnet_spec
let capella_slot = mainnet_spec
.fork_epoch(fork)
.unwrap()
.start_slot(MainnetEthSpec::slots_per_epoch());
Expand All @@ -130,15 +130,21 @@ impl Service {
.unwrap();

// Build the merge fork context
let merge_fork_context =
ForkContext::new::<MainnetEthSpec>(merge_slot, genesis_validators_root, &mainnet_spec);
let capella_fork_context = ForkContext::new::<MainnetEthSpec>(
capella_slot,
genesis_validators_root,
&mainnet_spec,
);

let fork_digest = capella_fork_context.to_context_bytes(fork).unwrap();
info!(slot = ?capella_slot, "Fork digest: {:?}", fork_digest);

// Build the network service context
let ctx = Context {
config: &network_config,
enr_fork_id: mainnet_spec
.enr_fork_id::<MainnetEthSpec>(merge_slot, genesis_validators_root),
fork_context: Arc::new(merge_fork_context),
.enr_fork_id::<MainnetEthSpec>(capella_slot, genesis_validators_root),
fork_context: Arc::new(capella_fork_context),
chain_spec: &mainnet_spec,
gossipsub_registry: None,
};
Expand All @@ -147,17 +153,17 @@ impl Service {

// Set a random default status (for now)
let mut highest_status = StatusMessage {
fork_digest: [74, 38, 197, 139],
fork_digest,
finalized_root: Hash256::from_str(
"0x6e1fbcfc857c0f849e4570009422edf1d56e29b16098b632fa8bee1b7e7f353c",
"0xb6adca904a0674b7263f8f9518b2a0dff5ee6089ee92890e742d0a64a2cbbb43",
)
.unwrap(),
finalized_epoch: Epoch::new(169022),
finalized_epoch: Epoch::new(194863),
head_root: Hash256::from_str(
"0xf4cc483036e8ec382ccc85639695b0bb12ed11e9c8af2daf5b0c5340b015ca4e",
"0xb41d25d17ef959d15aabdc01df99e2ec94dd600a0ac218d5b79b2a95cb14acad",
)
.unwrap(),
head_slot: Slot::new(5408793),
head_slot: Slot::new(6235698),
};

let mut epoch_blocks: VecDeque<(Slot, Hash256)> = VecDeque::with_capacity(3);
Expand Down
Loading

0 comments on commit dd1b5fd

Please sign in to comment.