mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 08:41:43 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b354a83faa | ||
|
|
0b287f6ece | ||
|
|
ee036cba7e | ||
|
|
f4fe2ac533 | ||
|
|
7d87e11e0f | ||
|
|
cfae5fbbc4 | ||
|
|
983f768034 | ||
|
|
138c0cf7f0 | ||
|
|
82a0973935 | ||
|
|
09a615b2c0 | ||
|
|
924ba66218 | ||
|
|
6206d8e79b | ||
|
|
5629126f45 | ||
|
|
20ee893969 | ||
|
|
0feb3cf19a |
@@ -2,4 +2,3 @@ tests/ef_tests/eth2.0-spec-tests
|
||||
target/
|
||||
*.data
|
||||
*.tar.gz
|
||||
.git
|
||||
|
||||
38
Cargo.lock
generated
38
Cargo.lock
generated
@@ -2,7 +2,7 @@
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "account_manager"
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"account_utils",
|
||||
"bls",
|
||||
@@ -357,7 +357,7 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "beacon_chain"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bls",
|
||||
@@ -407,7 +407,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "beacon_node"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"beacon_chain",
|
||||
"clap",
|
||||
@@ -766,7 +766,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "client"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"beacon_chain",
|
||||
"bus",
|
||||
@@ -1417,7 +1417,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "eth1"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"environment",
|
||||
"eth1_test_rig",
|
||||
@@ -1528,7 +1528,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "eth2_libp2p"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"dirs",
|
||||
@@ -1979,7 +1979,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "genesis"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"environment",
|
||||
"eth1",
|
||||
@@ -2978,7 +2978,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lighthouse"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"account_manager",
|
||||
"account_utils",
|
||||
@@ -3351,7 +3351,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "network"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"beacon_chain",
|
||||
"environment",
|
||||
@@ -3567,7 +3567,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "operation_pool"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"eth2_ssz",
|
||||
"eth2_ssz_derive",
|
||||
@@ -4333,7 +4333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rest_api"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"beacon_chain",
|
||||
@@ -5168,7 +5168,7 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
|
||||
[[package]]
|
||||
name = "store"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"db-key",
|
||||
@@ -5248,9 +5248,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.36"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
|
||||
checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5429,7 +5429,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "timer"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"beacon_chain",
|
||||
"environment",
|
||||
@@ -5975,9 +5975,9 @@ checksum = "c6ff93345ba2206230b1bb1aa3ece1a63dd9443b7531024575d16a0680a59444"
|
||||
|
||||
[[package]]
|
||||
name = "uint"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173cd16430c206dc1a430af8a89a0e9c076cf15cb42b4aedb10e8cc8fee73681"
|
||||
checksum = "429ffcad8c8c15f874578c7337d156a3727eb4a1c2374c0ae937ad9a9b748c80"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"byteorder",
|
||||
@@ -6121,7 +6121,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "validator_client"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"account_utils",
|
||||
"bls",
|
||||
@@ -6447,7 +6447,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "websocket_server"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"environment",
|
||||
"futures 0.3.5",
|
||||
|
||||
@@ -22,8 +22,7 @@ An open-source Ethereum 2.0 client, written in Rust and maintained by Sigma Prim
|
||||
Lighthouse is:
|
||||
|
||||
- Fully open-source, licensed under Apache 2.0.
|
||||
- Security-focused. Fuzzing has begun and security reviews are planned
|
||||
for late-2019.
|
||||
- Security-focused. Fuzzing has begun and security reviews are underway.
|
||||
- Built in [Rust](https://www.rust-lang.org/), a modern language providing unique safety guarantees and
|
||||
excellent performance (comparable to C++).
|
||||
- Funded by various organisations, including Sigma Prime, the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "account_manager"
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Luke Anderson <luke@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "beacon_node"
|
||||
version = "0.1.2"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Sigma Prime <contact@sigmaprime.io>"]
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "beacon_chain"
|
||||
version = "0.1.2"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -71,14 +71,14 @@ pub const FORK_CHOICE_DB_KEY: [u8; 32] = [0; 32];
|
||||
|
||||
/// The result of a chain segment processing.
|
||||
#[derive(Debug)]
|
||||
pub enum ChainSegmentResult {
|
||||
pub enum ChainSegmentResult<T: EthSpec> {
|
||||
/// Processing this chain segment finished successfully.
|
||||
Successful { imported_blocks: usize },
|
||||
/// There was an error processing this chain segment. Before the error, some blocks could
|
||||
/// have been imported.
|
||||
Failed {
|
||||
imported_blocks: usize,
|
||||
error: BlockError,
|
||||
error: BlockError<T>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
||||
///
|
||||
/// This pool accepts `Attestation` objects that only have one aggregation bit set and provides
|
||||
/// a method to get an aggregated `Attestation` for some `AttestationData`.
|
||||
pub naive_aggregation_pool: NaiveAggregationPool<T::EthSpec>,
|
||||
pub naive_aggregation_pool: RwLock<NaiveAggregationPool<T::EthSpec>>,
|
||||
/// Contains a store of attestations which have been observed by the beacon chain.
|
||||
pub observed_attestations: ObservedAttestations<T::EthSpec>,
|
||||
/// Maintains a record of which validators have been seen to attest in recent epochs.
|
||||
@@ -747,7 +747,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
&self,
|
||||
data: &AttestationData,
|
||||
) -> Result<Option<Attestation<T::EthSpec>>, Error> {
|
||||
self.naive_aggregation_pool.get(data).map_err(Into::into)
|
||||
self.naive_aggregation_pool
|
||||
.read()
|
||||
.get(data)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Produce an unaggregated `Attestation` that is valid for the given `slot` and `index`.
|
||||
@@ -937,7 +940,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
let attestation = unaggregated_attestation.attestation();
|
||||
|
||||
match self.naive_aggregation_pool.insert(attestation) {
|
||||
match self.naive_aggregation_pool.write().insert(attestation) {
|
||||
Ok(outcome) => trace!(
|
||||
self.log,
|
||||
"Stored unaggregated attestation";
|
||||
@@ -1153,7 +1156,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn process_chain_segment(
|
||||
&self,
|
||||
chain_segment: Vec<SignedBeaconBlock<T::EthSpec>>,
|
||||
) -> ChainSegmentResult {
|
||||
) -> ChainSegmentResult<T::EthSpec> {
|
||||
let mut filtered_chain_segment = Vec::with_capacity(chain_segment.len());
|
||||
let mut imported_blocks = 0;
|
||||
|
||||
@@ -1286,7 +1289,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn verify_block_for_gossip(
|
||||
&self,
|
||||
block: SignedBeaconBlock<T::EthSpec>,
|
||||
) -> Result<GossipVerifiedBlock<T>, BlockError> {
|
||||
) -> Result<GossipVerifiedBlock<T>, BlockError<T::EthSpec>> {
|
||||
let slot = block.message.slot;
|
||||
let graffiti_string = String::from_utf8(block.message.body.graffiti[..].to_vec())
|
||||
.unwrap_or_else(|_| format!("{:?}", &block.message.body.graffiti[..]));
|
||||
@@ -1332,7 +1335,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn process_block<B: IntoFullyVerifiedBlock<T>>(
|
||||
&self,
|
||||
unverified_block: B,
|
||||
) -> Result<Hash256, BlockError> {
|
||||
) -> Result<Hash256, BlockError<T::EthSpec>> {
|
||||
// Start the Prometheus timer.
|
||||
let _full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES);
|
||||
|
||||
@@ -1343,7 +1346,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let block = unverified_block.block().clone();
|
||||
|
||||
// A small closure to group the verification and import errors.
|
||||
let import_block = |unverified_block: B| -> Result<Hash256, BlockError> {
|
||||
let import_block = |unverified_block: B| -> Result<Hash256, BlockError<T::EthSpec>> {
|
||||
let fully_verified = unverified_block.into_fully_verified_block(self)?;
|
||||
self.import_block(fully_verified)
|
||||
};
|
||||
@@ -1411,7 +1414,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
fn import_block(
|
||||
&self,
|
||||
fully_verified_block: FullyVerifiedBlock<T>,
|
||||
) -> Result<Hash256, BlockError> {
|
||||
) -> Result<Hash256, BlockError<T::EthSpec>> {
|
||||
let signed_block = fully_verified_block.block;
|
||||
let block = &signed_block.message;
|
||||
let block_root = fully_verified_block.block_root;
|
||||
@@ -1632,6 +1635,24 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
})
|
||||
};
|
||||
|
||||
// Iterate through the naive aggregation pool and ensure all the attestations from there
|
||||
// are included in the operation pool.
|
||||
for attestation in self.naive_aggregation_pool.read().iter() {
|
||||
if let Err(e) = self.op_pool.insert_attestation(
|
||||
attestation.clone(),
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&self.spec,
|
||||
) {
|
||||
// Don't stop block production if there's an error, just create a log.
|
||||
error!(
|
||||
self.log,
|
||||
"Attestation did not transfer to op pool";
|
||||
"reason" => format!("{:?}", e)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut block = SignedBeaconBlock {
|
||||
message: BeaconBlock {
|
||||
slot: state.slot,
|
||||
@@ -1852,7 +1873,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn per_slot_task(&self) {
|
||||
trace!(self.log, "Running beacon chain per slot tasks");
|
||||
if let Some(slot) = self.slot_clock.now() {
|
||||
self.naive_aggregation_pool.prune(slot);
|
||||
self.naive_aggregation_pool.write().prune(slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2133,8 +2154,8 @@ impl From<BeaconStateError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainSegmentResult {
|
||||
pub fn into_block_error(self) -> Result<(), BlockError> {
|
||||
impl<T: EthSpec> ChainSegmentResult<T> {
|
||||
pub fn into_block_error(self) -> Result<(), BlockError<T>> {
|
||||
match self {
|
||||
ChainSegmentResult::Failed { error, .. } => Err(error),
|
||||
ChainSegmentResult::Successful { .. } => Ok(()),
|
||||
|
||||
@@ -83,14 +83,14 @@ const WRITE_BLOCK_PROCESSING_SSZ: bool = cfg!(feature = "write_ssz_files");
|
||||
/// - The block is malformed/invalid (indicated by all results other than `BeaconChainError`.
|
||||
/// - We encountered an error whilst trying to verify the block (a `BeaconChainError`).
|
||||
#[derive(Debug)]
|
||||
pub enum BlockError {
|
||||
pub enum BlockError<T: EthSpec> {
|
||||
/// The parent block was unknown.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// It's unclear if this block is valid, but it cannot be processed without already knowing
|
||||
/// its parent.
|
||||
ParentUnknown(Hash256),
|
||||
ParentUnknown(Box<SignedBeaconBlock<T>>),
|
||||
/// The block slot is greater than the present slot.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -199,7 +199,7 @@ pub enum BlockError {
|
||||
BeaconChainError(BeaconChainError),
|
||||
}
|
||||
|
||||
impl From<BlockSignatureVerifierError> for BlockError {
|
||||
impl<T: EthSpec> From<BlockSignatureVerifierError> for BlockError<T> {
|
||||
fn from(e: BlockSignatureVerifierError) -> Self {
|
||||
match e {
|
||||
// Make a special distinction for `IncorrectBlockProposer` since it indicates an
|
||||
@@ -216,25 +216,25 @@ impl From<BlockSignatureVerifierError> for BlockError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BeaconChainError> for BlockError {
|
||||
impl<T: EthSpec> From<BeaconChainError> for BlockError<T> {
|
||||
fn from(e: BeaconChainError) -> Self {
|
||||
BlockError::BeaconChainError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for BlockError {
|
||||
impl<T: EthSpec> From<BeaconStateError> for BlockError<T> {
|
||||
fn from(e: BeaconStateError) -> Self {
|
||||
BlockError::BeaconChainError(BeaconChainError::BeaconStateError(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SlotProcessingError> for BlockError {
|
||||
impl<T: EthSpec> From<SlotProcessingError> for BlockError<T> {
|
||||
fn from(e: SlotProcessingError) -> Self {
|
||||
BlockError::BeaconChainError(BeaconChainError::SlotProcessingError(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DBError> for BlockError {
|
||||
impl<T: EthSpec> From<DBError> for BlockError<T> {
|
||||
fn from(e: DBError) -> Self {
|
||||
BlockError::BeaconChainError(BeaconChainError::DBError(e))
|
||||
}
|
||||
@@ -251,15 +251,17 @@ impl From<DBError> for BlockError {
|
||||
/// The given `chain_segment` must span no more than two epochs, otherwise an error will be
|
||||
/// returned.
|
||||
pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
|
||||
chain_segment: Vec<(Hash256, SignedBeaconBlock<T::EthSpec>)>,
|
||||
mut chain_segment: Vec<(Hash256, SignedBeaconBlock<T::EthSpec>)>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Vec<SignatureVerifiedBlock<T>>, BlockError> {
|
||||
let (mut parent, slot) = if let Some(block) = chain_segment.first().map(|(_, block)| block) {
|
||||
let parent = load_parent(&block.message, chain)?;
|
||||
(parent, block.slot())
|
||||
} else {
|
||||
) -> Result<Vec<SignatureVerifiedBlock<T>>, BlockError<T::EthSpec>> {
|
||||
if chain_segment.is_empty() {
|
||||
return Ok(vec![]);
|
||||
};
|
||||
}
|
||||
|
||||
let (first_root, first_block) = chain_segment.remove(0);
|
||||
let (mut parent, first_block) = load_parent(first_block, chain)?;
|
||||
let slot = first_block.slot();
|
||||
chain_segment.insert(0, (first_root, first_block));
|
||||
|
||||
let highest_slot = chain_segment
|
||||
.last()
|
||||
@@ -343,7 +345,7 @@ pub trait IntoFullyVerifiedBlock<T: BeaconChainTypes> {
|
||||
fn into_fully_verified_block(
|
||||
self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError>;
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError<T::EthSpec>>;
|
||||
|
||||
fn block(&self) -> &SignedBeaconBlock<T::EthSpec>;
|
||||
}
|
||||
@@ -356,7 +358,7 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
pub fn new(
|
||||
block: SignedBeaconBlock<T::EthSpec>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Self, BlockError> {
|
||||
) -> Result<Self, BlockError<T::EthSpec>> {
|
||||
// Do not gossip or process blocks from future slots.
|
||||
let present_slot_with_tolerance = chain
|
||||
.slot_clock
|
||||
@@ -384,7 +386,7 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
});
|
||||
}
|
||||
|
||||
let mut parent = load_parent(&block.message, chain)?;
|
||||
let (mut parent, block) = load_parent(block, chain)?;
|
||||
let block_root = get_block_root(&block);
|
||||
|
||||
let state = cheap_state_advance_to_obtain_committees(
|
||||
@@ -453,7 +455,7 @@ impl<T: BeaconChainTypes> IntoFullyVerifiedBlock<T> for GossipVerifiedBlock<T> {
|
||||
fn into_fully_verified_block(
|
||||
self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError> {
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError<T::EthSpec>> {
|
||||
let fully_verified = SignatureVerifiedBlock::from_gossip_verified_block(self, chain)?;
|
||||
fully_verified.into_fully_verified_block(chain)
|
||||
}
|
||||
@@ -471,8 +473,8 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
|
||||
pub fn new(
|
||||
block: SignedBeaconBlock<T::EthSpec>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Self, BlockError> {
|
||||
let mut parent = load_parent(&block.message, chain)?;
|
||||
) -> Result<Self, BlockError<T::EthSpec>> {
|
||||
let (mut parent, block) = load_parent(block, chain)?;
|
||||
let block_root = get_block_root(&block);
|
||||
|
||||
let state = cheap_state_advance_to_obtain_committees(
|
||||
@@ -503,7 +505,7 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
|
||||
pub fn from_gossip_verified_block(
|
||||
from: GossipVerifiedBlock<T>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Self, BlockError> {
|
||||
) -> Result<Self, BlockError<T::EthSpec>> {
|
||||
let mut parent = from.parent;
|
||||
let block = from.block;
|
||||
|
||||
@@ -536,12 +538,12 @@ impl<T: BeaconChainTypes> IntoFullyVerifiedBlock<T> for SignatureVerifiedBlock<T
|
||||
fn into_fully_verified_block(
|
||||
self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError> {
|
||||
let block = self.block;
|
||||
let parent = self
|
||||
.parent
|
||||
.map(Result::Ok)
|
||||
.unwrap_or_else(|| load_parent(&block.message, chain))?;
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError<T::EthSpec>> {
|
||||
let (parent, block) = if let Some(parent) = self.parent {
|
||||
(parent, self.block)
|
||||
} else {
|
||||
load_parent(self.block, chain)?
|
||||
};
|
||||
|
||||
FullyVerifiedBlock::from_signature_verified_components(
|
||||
block,
|
||||
@@ -562,7 +564,7 @@ impl<T: BeaconChainTypes> IntoFullyVerifiedBlock<T> for SignedBeaconBlock<T::Eth
|
||||
fn into_fully_verified_block(
|
||||
self,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError> {
|
||||
) -> Result<FullyVerifiedBlock<T>, BlockError<T::EthSpec>> {
|
||||
SignatureVerifiedBlock::new(self, chain)?.into_fully_verified_block(chain)
|
||||
}
|
||||
|
||||
@@ -584,7 +586,7 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
|
||||
block_root: Hash256,
|
||||
parent: BeaconSnapshot<T::EthSpec>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Self, BlockError> {
|
||||
) -> Result<Self, BlockError<T::EthSpec>> {
|
||||
// Reject any block if its parent is not known to fork choice.
|
||||
//
|
||||
// A block that is not in fork choice is either:
|
||||
@@ -600,7 +602,7 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
|
||||
.read()
|
||||
.contains_block(&block.parent_root())
|
||||
{
|
||||
return Err(BlockError::ParentUnknown(block.parent_root()));
|
||||
return Err(BlockError::ParentUnknown(Box::new(block)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -749,7 +751,7 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
|
||||
fn check_block_against_finalized_slot<T: BeaconChainTypes>(
|
||||
block: &BeaconBlock<T::EthSpec>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<(), BlockError> {
|
||||
) -> Result<(), BlockError<T::EthSpec>> {
|
||||
let finalized_slot = chain
|
||||
.head_info()?
|
||||
.finalized_checkpoint
|
||||
@@ -777,7 +779,7 @@ pub fn check_block_relevancy<T: BeaconChainTypes>(
|
||||
signed_block: &SignedBeaconBlock<T::EthSpec>,
|
||||
block_root: Option<Hash256>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Hash256, BlockError> {
|
||||
) -> Result<Hash256, BlockError<T::EthSpec>> {
|
||||
let block = &signed_block.message;
|
||||
|
||||
// Do not process blocks from the future.
|
||||
@@ -830,12 +832,11 @@ pub fn get_block_root<E: EthSpec>(block: &SignedBeaconBlock<E>) -> Hash256 {
|
||||
///
|
||||
/// Returns `Err(BlockError::ParentUnknown)` if the parent is not found, or if an error occurs
|
||||
/// whilst attempting the operation.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn load_parent<T: BeaconChainTypes>(
|
||||
block: &BeaconBlock<T::EthSpec>,
|
||||
block: SignedBeaconBlock<T::EthSpec>,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<BeaconSnapshot<T::EthSpec>, BlockError> {
|
||||
let db_read_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_DB_READ);
|
||||
|
||||
) -> Result<(BeaconSnapshot<T::EthSpec>, SignedBeaconBlock<T::EthSpec>), BlockError<T::EthSpec>> {
|
||||
// Reject any block if its parent is not known to fork choice.
|
||||
//
|
||||
// A block that is not in fork choice is either:
|
||||
@@ -846,50 +847,58 @@ fn load_parent<T: BeaconChainTypes>(
|
||||
// because it will revert finalization. Note that the finalized block is stored in fork
|
||||
// choice, so we will not reject any child of the finalized block (this is relevant during
|
||||
// genesis).
|
||||
if !chain.fork_choice.read().contains_block(&block.parent_root) {
|
||||
return Err(BlockError::ParentUnknown(block.parent_root));
|
||||
if !chain
|
||||
.fork_choice
|
||||
.read()
|
||||
.contains_block(&block.parent_root())
|
||||
{
|
||||
return Err(BlockError::ParentUnknown(Box::new(block)));
|
||||
}
|
||||
|
||||
// Load the parent block and state from disk, returning early if it's not available.
|
||||
let result = chain
|
||||
let db_read_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_DB_READ);
|
||||
|
||||
let result = if let Some(snapshot) = chain
|
||||
.snapshot_cache
|
||||
.try_write_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT)
|
||||
.and_then(|mut snapshot_cache| snapshot_cache.try_remove(block.parent_root))
|
||||
.map(|snapshot| Ok(Some(snapshot)))
|
||||
.unwrap_or_else(|| {
|
||||
// Load the blocks parent block from the database, returning invalid if that block is not
|
||||
// found.
|
||||
//
|
||||
// We don't return a DBInconsistent error here since it's possible for a block to
|
||||
// exist in fork choice but not in the database yet. In such a case we simply
|
||||
// indicate that we don't yet know the parent.
|
||||
let parent_block = if let Some(block) = chain.get_block(&block.parent_root)? {
|
||||
block
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
.and_then(|mut snapshot_cache| snapshot_cache.try_remove(block.parent_root()))
|
||||
{
|
||||
Ok((snapshot, block))
|
||||
} else {
|
||||
// Load the blocks parent block from the database, returning invalid if that block is not
|
||||
// found.
|
||||
//
|
||||
// We don't return a DBInconsistent error here since it's possible for a block to
|
||||
// exist in fork choice but not in the database yet. In such a case we simply
|
||||
// indicate that we don't yet know the parent.
|
||||
let root = block.parent_root();
|
||||
let parent_block = if let Some(block) = chain
|
||||
.get_block(&block.parent_root())
|
||||
.map_err(BlockError::BeaconChainError)?
|
||||
{
|
||||
block
|
||||
} else {
|
||||
return Err(BlockError::ParentUnknown(Box::new(block)));
|
||||
};
|
||||
|
||||
// Load the parent blocks state from the database, returning an error if it is not found.
|
||||
// It is an error because if we know the parent block we should also know the parent state.
|
||||
let parent_state_root = parent_block.state_root();
|
||||
let parent_state = chain
|
||||
.get_state(&parent_state_root, Some(parent_block.slot()))?
|
||||
.ok_or_else(|| {
|
||||
BeaconChainError::DBInconsistent(format!(
|
||||
"Missing state {:?}",
|
||||
parent_state_root
|
||||
))
|
||||
})?;
|
||||
// Load the parent blocks state from the database, returning an error if it is not found.
|
||||
// It is an error because if we know the parent block we should also know the parent state.
|
||||
let parent_state_root = parent_block.state_root();
|
||||
let parent_state = chain
|
||||
.get_state(&parent_state_root, Some(parent_block.slot()))?
|
||||
.ok_or_else(|| {
|
||||
BeaconChainError::DBInconsistent(format!("Missing state {:?}", parent_state_root))
|
||||
})?;
|
||||
|
||||
Ok(Some(BeaconSnapshot {
|
||||
Ok((
|
||||
BeaconSnapshot {
|
||||
beacon_block: parent_block,
|
||||
beacon_block_root: block.parent_root,
|
||||
beacon_block_root: root,
|
||||
beacon_state: parent_state,
|
||||
beacon_state_root: parent_state_root,
|
||||
}))
|
||||
})
|
||||
.map_err(BlockError::BeaconChainError)?
|
||||
.ok_or_else(|| BlockError::ParentUnknown(block.parent_root));
|
||||
},
|
||||
block,
|
||||
))
|
||||
};
|
||||
|
||||
metrics::stop_timer(db_read_timer);
|
||||
|
||||
@@ -911,7 +920,7 @@ fn cheap_state_advance_to_obtain_committees<'a, E: EthSpec>(
|
||||
state: &'a mut BeaconState<E>,
|
||||
block_slot: Slot,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Cow<'a, BeaconState<E>>, BlockError> {
|
||||
) -> Result<Cow<'a, BeaconState<E>>, BlockError<E>> {
|
||||
let block_epoch = block_slot.epoch(E::slots_per_epoch());
|
||||
|
||||
if state.current_epoch() == block_epoch {
|
||||
@@ -943,7 +952,7 @@ fn cheap_state_advance_to_obtain_committees<'a, E: EthSpec>(
|
||||
/// Obtains a read-locked `ValidatorPubkeyCache` from the `chain`.
|
||||
fn get_validator_pubkey_cache<T: BeaconChainTypes>(
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<RwLockReadGuard<ValidatorPubkeyCache>, BlockError> {
|
||||
) -> Result<RwLockReadGuard<ValidatorPubkeyCache>, BlockError<T::EthSpec>> {
|
||||
chain
|
||||
.validator_pubkey_cache
|
||||
.try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::metrics;
|
||||
use parking_lot::RwLock;
|
||||
use std::collections::HashMap;
|
||||
use types::{Attestation, AttestationData, EthSpec, Slot};
|
||||
|
||||
@@ -120,6 +119,11 @@ impl<E: EthSpec> AggregatedAttestationMap<E> {
|
||||
Ok(self.map.get(data).cloned())
|
||||
}
|
||||
|
||||
/// Iterate all attestations in `self`.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Attestation<E>> {
|
||||
self.map.iter().map(|(_key, attestation)| attestation)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.map.len()
|
||||
}
|
||||
@@ -147,15 +151,15 @@ impl<E: EthSpec> AggregatedAttestationMap<E> {
|
||||
/// than that will also be refused. Pruning is done automatically based upon the attestations it
|
||||
/// receives and it can be triggered manually.
|
||||
pub struct NaiveAggregationPool<E: EthSpec> {
|
||||
lowest_permissible_slot: RwLock<Slot>,
|
||||
maps: RwLock<HashMap<Slot, AggregatedAttestationMap<E>>>,
|
||||
lowest_permissible_slot: Slot,
|
||||
maps: HashMap<Slot, AggregatedAttestationMap<E>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Default for NaiveAggregationPool<E> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
lowest_permissible_slot: RwLock::new(Slot::new(0)),
|
||||
maps: RwLock::new(HashMap::new()),
|
||||
lowest_permissible_slot: Slot::new(0),
|
||||
maps: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,10 +172,10 @@ impl<E: EthSpec> NaiveAggregationPool<E> {
|
||||
///
|
||||
/// The pool may be pruned if the given `attestation.data` has a slot higher than any
|
||||
/// previously seen.
|
||||
pub fn insert(&self, attestation: &Attestation<E>) -> Result<InsertOutcome, Error> {
|
||||
pub fn insert(&mut self, attestation: &Attestation<E>) -> Result<InsertOutcome, Error> {
|
||||
let _timer = metrics::start_timer(&metrics::ATTESTATION_PROCESSING_AGG_POOL_INSERT);
|
||||
let slot = attestation.data.slot;
|
||||
let lowest_permissible_slot: Slot = *self.lowest_permissible_slot.read();
|
||||
let lowest_permissible_slot = self.lowest_permissible_slot;
|
||||
|
||||
// Reject any attestations that are too old.
|
||||
if slot < lowest_permissible_slot {
|
||||
@@ -183,16 +187,16 @@ impl<E: EthSpec> NaiveAggregationPool<E> {
|
||||
|
||||
let lock_timer =
|
||||
metrics::start_timer(&metrics::ATTESTATION_PROCESSING_AGG_POOL_MAPS_WRITE_LOCK);
|
||||
let mut maps = self.maps.write();
|
||||
drop(lock_timer);
|
||||
|
||||
let outcome = if let Some(map) = maps.get_mut(&slot) {
|
||||
let outcome = if let Some(map) = self.maps.get_mut(&slot) {
|
||||
map.insert(attestation)
|
||||
} else {
|
||||
let _timer = metrics::start_timer(&metrics::ATTESTATION_PROCESSING_AGG_POOL_CREATE_MAP);
|
||||
// To avoid re-allocations, try and determine a rough initial capacity for the new item
|
||||
// by obtaining the mean size of all items in earlier epoch.
|
||||
let (count, sum) = maps
|
||||
let (count, sum) = self
|
||||
.maps
|
||||
.iter()
|
||||
// Only include epochs that are less than the given slot in the average. This should
|
||||
// generally avoid including recent epochs that are still "filling up".
|
||||
@@ -205,12 +209,11 @@ impl<E: EthSpec> NaiveAggregationPool<E> {
|
||||
|
||||
let mut item = AggregatedAttestationMap::new(initial_capacity);
|
||||
let outcome = item.insert(attestation);
|
||||
maps.insert(slot, item);
|
||||
self.maps.insert(slot, item);
|
||||
|
||||
outcome
|
||||
};
|
||||
|
||||
drop(maps);
|
||||
self.prune(slot);
|
||||
|
||||
outcome
|
||||
@@ -219,16 +222,20 @@ impl<E: EthSpec> NaiveAggregationPool<E> {
|
||||
/// Returns an aggregated `Attestation` with the given `data`, if any.
|
||||
pub fn get(&self, data: &AttestationData) -> Result<Option<Attestation<E>>, Error> {
|
||||
self.maps
|
||||
.read()
|
||||
.iter()
|
||||
.find(|(slot, _map)| **slot == data.slot)
|
||||
.map(|(_slot, map)| map.get(data))
|
||||
.unwrap_or_else(|| Ok(None))
|
||||
}
|
||||
|
||||
/// Iterate all attestations in all slots of `self`.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Attestation<E>> {
|
||||
self.maps.iter().map(|(_slot, map)| map.iter()).flatten()
|
||||
}
|
||||
|
||||
/// Removes any attestations with a slot lower than `current_slot` and bars any future
|
||||
/// attestations with a slot lower than `current_slot - SLOTS_RETAINED`.
|
||||
pub fn prune(&self, current_slot: Slot) {
|
||||
pub fn prune(&mut self, current_slot: Slot) {
|
||||
let _timer = metrics::start_timer(&metrics::ATTESTATION_PROCESSING_AGG_POOL_PRUNE);
|
||||
|
||||
// Taking advantage of saturating subtraction on `Slot`.
|
||||
@@ -236,30 +243,34 @@ impl<E: EthSpec> NaiveAggregationPool<E> {
|
||||
|
||||
// No need to prune if the lowest permissible slot has not changed and the queue length is
|
||||
// less than the maximum
|
||||
if *self.lowest_permissible_slot.read() == lowest_permissible_slot
|
||||
&& self.maps.read().len() <= SLOTS_RETAINED
|
||||
if self.lowest_permissible_slot == lowest_permissible_slot
|
||||
&& self.maps.len() <= SLOTS_RETAINED
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*self.lowest_permissible_slot.write() = lowest_permissible_slot;
|
||||
let mut maps = self.maps.write();
|
||||
self.lowest_permissible_slot = lowest_permissible_slot;
|
||||
|
||||
// Remove any maps that are definitely expired.
|
||||
maps.retain(|slot, _map| *slot >= lowest_permissible_slot);
|
||||
self.maps
|
||||
.retain(|slot, _map| *slot >= lowest_permissible_slot);
|
||||
|
||||
// If we have too many maps, remove the lowest amount to ensure we only have
|
||||
// `SLOTS_RETAINED` left.
|
||||
if maps.len() > SLOTS_RETAINED {
|
||||
let mut slots = maps.iter().map(|(slot, _map)| *slot).collect::<Vec<_>>();
|
||||
if self.maps.len() > SLOTS_RETAINED {
|
||||
let mut slots = self
|
||||
.maps
|
||||
.iter()
|
||||
.map(|(slot, _map)| *slot)
|
||||
.collect::<Vec<_>>();
|
||||
// Sort is generally pretty slow, however `SLOTS_RETAINED` is quite low so it should be
|
||||
// negligible.
|
||||
slots.sort_unstable();
|
||||
slots
|
||||
.into_iter()
|
||||
.take(maps.len().saturating_sub(SLOTS_RETAINED))
|
||||
.take(self.maps.len().saturating_sub(SLOTS_RETAINED))
|
||||
.for_each(|slot| {
|
||||
maps.remove(&slot);
|
||||
self.maps.remove(&slot);
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -304,7 +315,7 @@ mod tests {
|
||||
fn single_attestation() {
|
||||
let mut a = get_attestation(Slot::new(0));
|
||||
|
||||
let pool = NaiveAggregationPool::default();
|
||||
let mut pool = NaiveAggregationPool::default();
|
||||
|
||||
assert_eq!(
|
||||
pool.insert(&a),
|
||||
@@ -352,7 +363,7 @@ mod tests {
|
||||
sign(&mut a_0, 0, genesis_validators_root);
|
||||
sign(&mut a_1, 1, genesis_validators_root);
|
||||
|
||||
let pool = NaiveAggregationPool::default();
|
||||
let mut pool = NaiveAggregationPool::default();
|
||||
|
||||
assert_eq!(
|
||||
pool.insert(&a_0),
|
||||
@@ -409,7 +420,7 @@ mod tests {
|
||||
let mut base = get_attestation(Slot::new(0));
|
||||
sign(&mut base, 0, Hash256::random());
|
||||
|
||||
let pool = NaiveAggregationPool::default();
|
||||
let mut pool = NaiveAggregationPool::default();
|
||||
|
||||
for i in 0..SLOTS_RETAINED * 2 {
|
||||
let slot = Slot::from(i);
|
||||
@@ -424,22 +435,16 @@ mod tests {
|
||||
|
||||
if i < SLOTS_RETAINED {
|
||||
let len = i + 1;
|
||||
assert_eq!(
|
||||
pool.maps.read().len(),
|
||||
len,
|
||||
"the pool should have length {}",
|
||||
len
|
||||
);
|
||||
assert_eq!(pool.maps.len(), len, "the pool should have length {}", len);
|
||||
} else {
|
||||
assert_eq!(
|
||||
pool.maps.read().len(),
|
||||
pool.maps.len(),
|
||||
SLOTS_RETAINED,
|
||||
"the pool should have length SLOTS_RETAINED"
|
||||
);
|
||||
|
||||
let mut pool_slots = pool
|
||||
.maps
|
||||
.read()
|
||||
.iter()
|
||||
.map(|(slot, _map)| *slot)
|
||||
.collect::<Vec<_>>();
|
||||
@@ -463,7 +468,7 @@ mod tests {
|
||||
let mut base = get_attestation(Slot::new(0));
|
||||
sign(&mut base, 0, Hash256::random());
|
||||
|
||||
let pool = NaiveAggregationPool::default();
|
||||
let mut pool = NaiveAggregationPool::default();
|
||||
|
||||
for i in 0..=MAX_ATTESTATIONS_PER_SLOT {
|
||||
let mut a = base.clone();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "eth1"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "eth2_libp2p"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -95,11 +95,18 @@ impl Default for Config {
|
||||
// parameter.
|
||||
let gs_config = GossipsubConfigBuilder::new()
|
||||
.max_transmit_size(GOSSIP_MAX_SIZE)
|
||||
.heartbeat_interval(Duration::from_secs(1))
|
||||
.heartbeat_interval(Duration::from_millis(700))
|
||||
.mesh_n(6)
|
||||
.mesh_n_low(5)
|
||||
.mesh_n_high(12)
|
||||
.gossip_lazy(6)
|
||||
.fanout_ttl(Duration::from_secs(60))
|
||||
.history_length(6)
|
||||
.history_gossip(3)
|
||||
.validate_messages() // require validation before propagation
|
||||
.validation_mode(ValidationMode::Permissive)
|
||||
// Prevent duplicates by caching messages from an epoch + 1 slot amount of time (33*12)
|
||||
.duplicate_cache_time(Duration::from_secs(396))
|
||||
// prevent duplicates for 550 heartbeats(700millis * 550) = 385 secs
|
||||
.duplicate_cache_time(Duration::from_secs(385))
|
||||
.message_id_fn(gossip_message_id)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -174,7 +174,6 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::ssz::*;
|
||||
use super::super::ssz_snappy::*;
|
||||
use super::*;
|
||||
use crate::rpc::protocol::*;
|
||||
@@ -189,29 +188,22 @@ mod tests {
|
||||
|
||||
let snappy_protocol_id =
|
||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy);
|
||||
let ssz_protocol_id = ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZ);
|
||||
|
||||
let mut snappy_outbound_codec =
|
||||
SSZSnappyOutboundCodec::<Spec>::new(snappy_protocol_id, 1_048_576);
|
||||
let mut ssz_outbound_codec = SSZOutboundCodec::<Spec>::new(ssz_protocol_id, 1_048_576);
|
||||
|
||||
// decode message just as snappy message
|
||||
let snappy_decoded_message = snappy_outbound_codec.decode(&mut buf.clone());
|
||||
// decode message just a ssz message
|
||||
let ssz_decoded_message = ssz_outbound_codec.decode(&mut buf.clone());
|
||||
|
||||
// build codecs for entire chunk
|
||||
let mut snappy_base_outbound_codec = BaseOutboundCodec::new(snappy_outbound_codec);
|
||||
let mut ssz_base_outbound_codec = BaseOutboundCodec::new(ssz_outbound_codec);
|
||||
|
||||
// decode message as ssz snappy chunk
|
||||
let snappy_decoded_chunk = snappy_base_outbound_codec.decode(&mut buf.clone());
|
||||
// decode message just a ssz chunk
|
||||
let ssz_decoded_chunk = ssz_base_outbound_codec.decode(&mut buf.clone());
|
||||
|
||||
let _ = dbg!(snappy_decoded_message);
|
||||
let _ = dbg!(ssz_decoded_message);
|
||||
let _ = dbg!(snappy_decoded_chunk);
|
||||
let _ = dbg!(ssz_decoded_chunk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
pub(crate) mod base;
|
||||
pub(crate) mod ssz;
|
||||
pub(crate) mod ssz_snappy;
|
||||
|
||||
use self::base::{BaseInboundCodec, BaseOutboundCodec};
|
||||
use self::ssz::{SSZInboundCodec, SSZOutboundCodec};
|
||||
use self::ssz_snappy::{SSZSnappyInboundCodec, SSZSnappyOutboundCodec};
|
||||
use crate::rpc::protocol::RPCError;
|
||||
use crate::rpc::{RPCCodedResponse, RPCRequest};
|
||||
@@ -14,12 +12,10 @@ use types::EthSpec;
|
||||
// Known types of codecs
|
||||
pub enum InboundCodec<TSpec: EthSpec> {
|
||||
SSZSnappy(BaseInboundCodec<SSZSnappyInboundCodec<TSpec>, TSpec>),
|
||||
SSZ(BaseInboundCodec<SSZInboundCodec<TSpec>, TSpec>),
|
||||
}
|
||||
|
||||
pub enum OutboundCodec<TSpec: EthSpec> {
|
||||
SSZSnappy(BaseOutboundCodec<SSZSnappyOutboundCodec<TSpec>, TSpec>),
|
||||
SSZ(BaseOutboundCodec<SSZOutboundCodec<TSpec>, TSpec>),
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Encoder<RPCCodedResponse<T>> for InboundCodec<T> {
|
||||
@@ -27,7 +23,6 @@ impl<T: EthSpec> Encoder<RPCCodedResponse<T>> for InboundCodec<T> {
|
||||
|
||||
fn encode(&mut self, item: RPCCodedResponse<T>, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
InboundCodec::SSZ(codec) => codec.encode(item, dst),
|
||||
InboundCodec::SSZSnappy(codec) => codec.encode(item, dst),
|
||||
}
|
||||
}
|
||||
@@ -39,7 +34,6 @@ impl<TSpec: EthSpec> Decoder for InboundCodec<TSpec> {
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
match self {
|
||||
InboundCodec::SSZ(codec) => codec.decode(src),
|
||||
InboundCodec::SSZSnappy(codec) => codec.decode(src),
|
||||
}
|
||||
}
|
||||
@@ -50,7 +44,6 @@ impl<TSpec: EthSpec> Encoder<RPCRequest<TSpec>> for OutboundCodec<TSpec> {
|
||||
|
||||
fn encode(&mut self, item: RPCRequest<TSpec>, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
OutboundCodec::SSZ(codec) => codec.encode(item, dst),
|
||||
OutboundCodec::SSZSnappy(codec) => codec.encode(item, dst),
|
||||
}
|
||||
}
|
||||
@@ -62,7 +55,6 @@ impl<T: EthSpec> Decoder for OutboundCodec<T> {
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
match self {
|
||||
OutboundCodec::SSZ(codec) => codec.decode(src),
|
||||
OutboundCodec::SSZSnappy(codec) => codec.decode(src),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,324 +0,0 @@
|
||||
use crate::rpc::methods::*;
|
||||
use crate::rpc::{
|
||||
codec::base::OutboundCodec,
|
||||
protocol::{
|
||||
Encoding, Protocol, ProtocolId, RPCError, Version, BLOCKS_BY_ROOT_REQUEST_MAX,
|
||||
BLOCKS_BY_ROOT_REQUEST_MIN, SIGNED_BEACON_BLOCK_MAX, SIGNED_BEACON_BLOCK_MIN,
|
||||
},
|
||||
};
|
||||
use crate::rpc::{RPCCodedResponse, RPCRequest, RPCResponse};
|
||||
use libp2p::bytes::{BufMut, Bytes, BytesMut};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use std::marker::PhantomData;
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
use types::{EthSpec, SignedBeaconBlock};
|
||||
use unsigned_varint::codec::UviBytes;
|
||||
|
||||
/* Inbound Codec */
|
||||
|
||||
pub struct SSZInboundCodec<TSpec: EthSpec> {
|
||||
inner: UviBytes,
|
||||
protocol: ProtocolId,
|
||||
phantom: PhantomData<TSpec>,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> SSZInboundCodec<TSpec> {
|
||||
pub fn new(protocol: ProtocolId, max_packet_size: usize) -> Self {
|
||||
let mut uvi_codec = UviBytes::default();
|
||||
uvi_codec.set_max_len(max_packet_size);
|
||||
|
||||
// this encoding only applies to ssz.
|
||||
debug_assert_eq!(protocol.encoding, Encoding::SSZ);
|
||||
|
||||
SSZInboundCodec {
|
||||
inner: uvi_codec,
|
||||
protocol,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encoder for inbound streams: Encodes RPC Responses sent to peers.
|
||||
impl<TSpec: EthSpec> Encoder<RPCCodedResponse<TSpec>> for SSZInboundCodec<TSpec> {
|
||||
type Error = RPCError;
|
||||
|
||||
fn encode(
|
||||
&mut self,
|
||||
item: RPCCodedResponse<TSpec>,
|
||||
dst: &mut BytesMut,
|
||||
) -> Result<(), Self::Error> {
|
||||
let bytes = match item {
|
||||
RPCCodedResponse::Success(resp) => match resp {
|
||||
RPCResponse::Status(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::BlocksByRange(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::Pong(res) => res.data.as_ssz_bytes(),
|
||||
RPCResponse::MetaData(res) => res.as_ssz_bytes(),
|
||||
},
|
||||
RPCCodedResponse::Error(_, err) => err.as_ssz_bytes(),
|
||||
RPCCodedResponse::StreamTermination(_) => {
|
||||
unreachable!("Code error - attempting to encode a stream termination")
|
||||
}
|
||||
};
|
||||
if !bytes.is_empty() {
|
||||
// length-prefix and return
|
||||
return self
|
||||
.inner
|
||||
.encode(Bytes::from(bytes), dst)
|
||||
.map_err(RPCError::from);
|
||||
} else {
|
||||
// payload is empty, add a 0-byte length prefix
|
||||
dst.reserve(1);
|
||||
dst.put_u8(0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Decoder for inbound streams: Decodes RPC requests from peers
|
||||
impl<TSpec: EthSpec> Decoder for SSZInboundCodec<TSpec> {
|
||||
type Item = RPCRequest<TSpec>;
|
||||
type Error = RPCError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
match self.inner.decode(src).map_err(RPCError::from) {
|
||||
Ok(Some(packet)) => match self.protocol.message_name {
|
||||
Protocol::Status => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if packet.len() == <StatusMessage as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCRequest::Status(StatusMessage::from_ssz_bytes(
|
||||
&packet,
|
||||
)?)))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::Goodbye => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if packet.len() == <GoodbyeReason as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCRequest::Goodbye(GoodbyeReason::from_ssz_bytes(
|
||||
&packet,
|
||||
)?)))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::BlocksByRange => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if packet.len() == <BlocksByRangeRequest as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCRequest::BlocksByRange(
|
||||
BlocksByRangeRequest::from_ssz_bytes(&packet)?,
|
||||
)))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::BlocksByRoot => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if packet.len() >= *BLOCKS_BY_ROOT_REQUEST_MIN
|
||||
&& packet.len() <= *BLOCKS_BY_ROOT_REQUEST_MAX
|
||||
{
|
||||
Ok(Some(RPCRequest::BlocksByRoot(BlocksByRootRequest {
|
||||
block_roots: VariableList::from_ssz_bytes(&packet)?,
|
||||
})))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::Ping => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if packet.len() == <Ping as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCRequest::Ping(Ping {
|
||||
data: u64::from_ssz_bytes(&packet)?,
|
||||
})))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::MetaData => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if !packet.is_empty() {
|
||||
Err(RPCError::InvalidData)
|
||||
} else {
|
||||
Ok(Some(RPCRequest::MetaData(PhantomData)))
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Outbound Codec: Codec for initiating RPC requests */
|
||||
|
||||
pub struct SSZOutboundCodec<TSpec: EthSpec> {
|
||||
inner: UviBytes,
|
||||
protocol: ProtocolId,
|
||||
phantom: PhantomData<TSpec>,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> SSZOutboundCodec<TSpec> {
|
||||
pub fn new(protocol: ProtocolId, max_packet_size: usize) -> Self {
|
||||
let mut uvi_codec = UviBytes::default();
|
||||
uvi_codec.set_max_len(max_packet_size);
|
||||
|
||||
// this encoding only applies to ssz.
|
||||
debug_assert_eq!(protocol.encoding, Encoding::SSZ);
|
||||
|
||||
SSZOutboundCodec {
|
||||
inner: uvi_codec,
|
||||
protocol,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encoder for outbound streams: Encodes RPC Requests to peers
|
||||
impl<TSpec: EthSpec> Encoder<RPCRequest<TSpec>> for SSZOutboundCodec<TSpec> {
|
||||
type Error = RPCError;
|
||||
|
||||
fn encode(&mut self, item: RPCRequest<TSpec>, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
let bytes = match item {
|
||||
RPCRequest::Status(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::Goodbye(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::BlocksByRange(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::BlocksByRoot(req) => req.block_roots.as_ssz_bytes(),
|
||||
RPCRequest::Ping(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::MetaData(_) => return Ok(()), // no metadata to encode
|
||||
};
|
||||
// length-prefix
|
||||
self.inner
|
||||
.encode(libp2p::bytes::Bytes::from(bytes), dst)
|
||||
.map_err(RPCError::from)
|
||||
}
|
||||
}
|
||||
|
||||
// Decoder for outbound streams: Decodes RPC responses from peers.
|
||||
//
|
||||
// The majority of the decoding has now been pushed upstream due to the changing specification.
|
||||
// We prefer to decode blocks and attestations with extra knowledge about the chain to perform
|
||||
// faster verification checks before decoding entire blocks/attestations.
|
||||
impl<TSpec: EthSpec> Decoder for SSZOutboundCodec<TSpec> {
|
||||
type Item = RPCResponse<TSpec>;
|
||||
type Error = RPCError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if src.len() == 1 && src[0] == 0_u8 {
|
||||
// the object is empty. We return the empty object if this is the case
|
||||
// clear the buffer and return an empty object
|
||||
src.clear();
|
||||
match self.protocol.message_name {
|
||||
Protocol::Status => match self.protocol.version {
|
||||
Version::V1 => Err(RPCError::IncompleteStream), // cannot have an empty HELLO message. The stream has terminated unexpectedly
|
||||
},
|
||||
Protocol::Goodbye => Err(RPCError::InvalidData),
|
||||
Protocol::BlocksByRange => match self.protocol.version {
|
||||
Version::V1 => Err(RPCError::IncompleteStream), // cannot have an empty block message.
|
||||
},
|
||||
Protocol::BlocksByRoot => match self.protocol.version {
|
||||
Version::V1 => Err(RPCError::IncompleteStream), // cannot have an empty block message.
|
||||
},
|
||||
Protocol::Ping => match self.protocol.version {
|
||||
Version::V1 => Err(RPCError::IncompleteStream), // cannot have an empty block message.
|
||||
},
|
||||
Protocol::MetaData => match self.protocol.version {
|
||||
Version::V1 => Err(RPCError::IncompleteStream), // cannot have an empty block message.
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match self.inner.decode(src).map_err(RPCError::from) {
|
||||
Ok(Some(mut packet)) => {
|
||||
// take the bytes from the buffer
|
||||
let raw_bytes = packet.split();
|
||||
|
||||
match self.protocol.message_name {
|
||||
Protocol::Status => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if raw_bytes.len() == <StatusMessage as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCResponse::Status(StatusMessage::from_ssz_bytes(
|
||||
&raw_bytes,
|
||||
)?)))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::Goodbye => Err(RPCError::InvalidData),
|
||||
Protocol::BlocksByRange => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if raw_bytes.len() >= *SIGNED_BEACON_BLOCK_MIN
|
||||
&& raw_bytes.len() <= *SIGNED_BEACON_BLOCK_MAX
|
||||
{
|
||||
Ok(Some(RPCResponse::BlocksByRange(Box::new(
|
||||
SignedBeaconBlock::from_ssz_bytes(&raw_bytes)?,
|
||||
))))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::BlocksByRoot => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if raw_bytes.len() >= *SIGNED_BEACON_BLOCK_MIN
|
||||
&& raw_bytes.len() <= *SIGNED_BEACON_BLOCK_MAX
|
||||
{
|
||||
Ok(Some(RPCResponse::BlocksByRoot(Box::new(
|
||||
SignedBeaconBlock::from_ssz_bytes(&raw_bytes)?,
|
||||
))))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::Ping => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if raw_bytes.len() == <Ping as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCResponse::Pong(Ping {
|
||||
data: u64::from_ssz_bytes(&raw_bytes)?,
|
||||
})))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
Protocol::MetaData => match self.protocol.version {
|
||||
Version::V1 => {
|
||||
if raw_bytes.len() == <MetaData<TSpec> as Encode>::ssz_fixed_len() {
|
||||
Ok(Some(RPCResponse::MetaData(MetaData::from_ssz_bytes(
|
||||
&raw_bytes,
|
||||
)?)))
|
||||
} else {
|
||||
Err(RPCError::InvalidData)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(None) => Ok(None), // waiting for more bytes
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> OutboundCodec<RPCRequest<TSpec>> for SSZOutboundCodec<TSpec> {
|
||||
type ErrorType = String;
|
||||
|
||||
fn decode_error(&mut self, src: &mut BytesMut) -> Result<Option<Self::ErrorType>, RPCError> {
|
||||
match self.inner.decode(src).map_err(RPCError::from) {
|
||||
Ok(Some(packet)) => Ok(Some(
|
||||
String::from_utf8_lossy(&<Vec<u8>>::from_ssz_bytes(&packet)?).into(),
|
||||
)),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ impl<T: EthSpec> std::fmt::Display for RPCCodedResponse<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RPCCodedResponse::Success(res) => write!(f, "{}", res),
|
||||
RPCCodedResponse::Error(code, err) => write!(f, "{}: {:?}", code, err),
|
||||
RPCCodedResponse::Error(code, err) => write!(f, "{}: {}", code, err.to_string()),
|
||||
RPCCodedResponse::StreamTermination(_) => write!(f, "Stream Termination"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use super::methods::*;
|
||||
use crate::rpc::{
|
||||
codec::{
|
||||
base::{BaseInboundCodec, BaseOutboundCodec},
|
||||
ssz::{SSZInboundCodec, SSZOutboundCodec},
|
||||
ssz_snappy::{SSZSnappyInboundCodec, SSZSnappyOutboundCodec},
|
||||
InboundCodec, OutboundCodec,
|
||||
},
|
||||
@@ -91,7 +90,6 @@ pub enum Version {
|
||||
/// RPC Encondings supported.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Encoding {
|
||||
SSZ,
|
||||
SSZSnappy,
|
||||
}
|
||||
|
||||
@@ -112,7 +110,6 @@ impl std::fmt::Display for Protocol {
|
||||
impl std::fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let repr = match self {
|
||||
Encoding::SSZ => "ssz",
|
||||
Encoding::SSZSnappy => "ssz_snappy",
|
||||
};
|
||||
f.write_str(repr)
|
||||
@@ -141,17 +138,11 @@ impl<TSpec: EthSpec> UpgradeInfo for RPCProtocol<TSpec> {
|
||||
fn protocol_info(&self) -> Self::InfoIter {
|
||||
vec![
|
||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZ),
|
||||
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZ),
|
||||
ProtocolId::new(Protocol::BlocksByRange, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::BlocksByRange, Version::V1, Encoding::SSZ),
|
||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V1, Encoding::SSZ),
|
||||
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZ),
|
||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZ),
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -224,11 +215,6 @@ where
|
||||
BaseInboundCodec::new(SSZSnappyInboundCodec::new(protocol, MAX_RPC_SIZE));
|
||||
InboundCodec::SSZSnappy(ssz_snappy_codec)
|
||||
}
|
||||
Encoding::SSZ => {
|
||||
let ssz_codec =
|
||||
BaseInboundCodec::new(SSZInboundCodec::new(protocol, MAX_RPC_SIZE));
|
||||
InboundCodec::SSZ(ssz_codec)
|
||||
}
|
||||
};
|
||||
let mut timed_socket = TimeoutStream::new(socket);
|
||||
timed_socket.set_read_timeout(Some(Duration::from_secs(TTFB_TIMEOUT)));
|
||||
@@ -286,30 +272,36 @@ impl<TSpec: EthSpec> RPCRequest<TSpec> {
|
||||
pub fn supported_protocols(&self) -> Vec<ProtocolId> {
|
||||
match self {
|
||||
// add more protocols when versions/encodings are supported
|
||||
RPCRequest::Status(_) => vec![
|
||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::Goodbye(_) => vec![
|
||||
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::BlocksByRange(_) => vec![
|
||||
ProtocolId::new(Protocol::BlocksByRange, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::BlocksByRange, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::BlocksByRoot(_) => vec![
|
||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::Ping(_) => vec![
|
||||
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::MetaData(_) => vec![
|
||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZ),
|
||||
],
|
||||
RPCRequest::Status(_) => vec![ProtocolId::new(
|
||||
Protocol::Status,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
RPCRequest::Goodbye(_) => vec![ProtocolId::new(
|
||||
Protocol::Goodbye,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
RPCRequest::BlocksByRange(_) => vec![ProtocolId::new(
|
||||
Protocol::BlocksByRange,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
RPCRequest::BlocksByRoot(_) => vec![ProtocolId::new(
|
||||
Protocol::BlocksByRoot,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
RPCRequest::Ping(_) => vec![ProtocolId::new(
|
||||
Protocol::Ping,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
RPCRequest::MetaData(_) => vec![ProtocolId::new(
|
||||
Protocol::MetaData,
|
||||
Version::V1,
|
||||
Encoding::SSZSnappy,
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,11 +371,6 @@ where
|
||||
BaseOutboundCodec::new(SSZSnappyOutboundCodec::new(protocol, MAX_RPC_SIZE));
|
||||
OutboundCodec::SSZSnappy(ssz_snappy_codec)
|
||||
}
|
||||
Encoding::SSZ => {
|
||||
let ssz_codec =
|
||||
BaseOutboundCodec::new(SSZOutboundCodec::new(protocol, MAX_RPC_SIZE));
|
||||
OutboundCodec::SSZ(ssz_codec)
|
||||
}
|
||||
};
|
||||
|
||||
let mut socket = Framed::new(socket, codec);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "genesis"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "network"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -240,13 +240,15 @@ impl<T: BeaconChainTypes> Router<T> {
|
||||
}
|
||||
}
|
||||
PubsubMessage::BeaconBlock(block) => {
|
||||
match self.processor.should_forward_block(&peer_id, block) {
|
||||
match self.processor.should_forward_block(block) {
|
||||
Ok(verified_block) => {
|
||||
info!(self.log, "New block received"; "slot" => verified_block.block.slot(), "hash" => verified_block.block_root.to_string());
|
||||
self.propagate_message(id, peer_id.clone());
|
||||
self.processor.on_block_gossip(peer_id, verified_block);
|
||||
}
|
||||
Err(BlockError::ParentUnknown { .. }) => {} // performing a parent lookup
|
||||
Err(BlockError::ParentUnknown(block)) => {
|
||||
self.processor.on_unknown_parent(peer_id, block);
|
||||
}
|
||||
Err(e) => {
|
||||
// performing a parent lookup
|
||||
warn!(self.log, "Could not verify block for gossip";
|
||||
@@ -260,7 +262,7 @@ impl<T: BeaconChainTypes> Router<T> {
|
||||
.processor
|
||||
.verify_voluntary_exit_for_gossip(&peer_id, *exit)
|
||||
{
|
||||
self.propagate_message(id, peer_id.clone());
|
||||
self.propagate_message(id, peer_id);
|
||||
self.processor.import_verified_voluntary_exit(verified_exit);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +276,7 @@ impl<T: BeaconChainTypes> Router<T> {
|
||||
.processor
|
||||
.verify_proposer_slashing_for_gossip(&peer_id, *proposer_slashing)
|
||||
{
|
||||
self.propagate_message(id, peer_id.clone());
|
||||
self.propagate_message(id, peer_id);
|
||||
self.processor
|
||||
.import_verified_proposer_slashing(verified_proposer_slashing);
|
||||
}
|
||||
@@ -289,7 +291,7 @@ impl<T: BeaconChainTypes> Router<T> {
|
||||
.processor
|
||||
.verify_attester_slashing_for_gossip(&peer_id, *attester_slashing)
|
||||
{
|
||||
self.propagate_message(id, peer_id.clone());
|
||||
self.propagate_message(id, peer_id);
|
||||
self.processor
|
||||
.import_verified_attester_slashing(verified_attester_slashing);
|
||||
}
|
||||
|
||||
@@ -503,17 +503,17 @@ impl<T: BeaconChainTypes> Processor<T> {
|
||||
/// across the network.
|
||||
pub fn should_forward_block(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
block: Box<SignedBeaconBlock<T::EthSpec>>,
|
||||
) -> Result<GossipVerifiedBlock<T>, BlockError> {
|
||||
let result = self.chain.verify_block_for_gossip(*block.clone());
|
||||
) -> Result<GossipVerifiedBlock<T>, BlockError<T::EthSpec>> {
|
||||
self.chain.verify_block_for_gossip(*block)
|
||||
}
|
||||
|
||||
if let Err(BlockError::ParentUnknown(_)) = result {
|
||||
// if we don't know the parent, start a parent lookup
|
||||
// TODO: Modify the return to avoid the block clone.
|
||||
self.send_to_sync(SyncMessage::UnknownBlock(peer_id.clone(), block));
|
||||
}
|
||||
result
|
||||
pub fn on_unknown_parent(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
block: Box<SignedBeaconBlock<T::EthSpec>>,
|
||||
) {
|
||||
self.send_to_sync(SyncMessage::UnknownBlock(peer_id, block));
|
||||
}
|
||||
|
||||
/// Process a gossip message declaring a new block.
|
||||
@@ -596,6 +596,7 @@ impl<T: BeaconChainTypes> Processor<T> {
|
||||
debug!(
|
||||
self.log,
|
||||
"Invalid attestation from network";
|
||||
"reason" => format!("{:?}", error),
|
||||
"block" => format!("{}", beacon_block_root),
|
||||
"peer_id" => peer_id.to_string(),
|
||||
"type" => format!("{:?}", attestation_type),
|
||||
|
||||
@@ -6,7 +6,7 @@ use eth2_libp2p::PeerId;
|
||||
use slog::{debug, error, trace, warn};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::mpsc;
|
||||
use types::SignedBeaconBlock;
|
||||
use types::{EthSpec, SignedBeaconBlock};
|
||||
|
||||
/// Id associated to a block processing request, either a batch or a single block.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -178,12 +178,18 @@ fn run_fork_choice<T: BeaconChainTypes>(chain: Arc<BeaconChain<T>>, log: &slog::
|
||||
}
|
||||
|
||||
/// Helper function to handle a `BlockError` from `process_chain_segment`
|
||||
fn handle_failed_chain_segment(error: BlockError, log: &slog::Logger) -> Result<(), String> {
|
||||
fn handle_failed_chain_segment<T: EthSpec>(
|
||||
error: BlockError<T>,
|
||||
log: &slog::Logger,
|
||||
) -> Result<(), String> {
|
||||
match error {
|
||||
BlockError::ParentUnknown(parent) => {
|
||||
BlockError::ParentUnknown(block) => {
|
||||
// blocks should be sequential and all parents should exist
|
||||
|
||||
Err(format!("Block has an unknown parent: {}", parent))
|
||||
Err(format!(
|
||||
"Block has an unknown parent: {}",
|
||||
block.parent_root()
|
||||
))
|
||||
}
|
||||
BlockError::BlockIsAlreadyKnown => {
|
||||
// This can happen for many reasons. Head sync's can download multiples and parent
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "operation_pool"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rest_api"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>", "Luke Anderson <luke@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "store"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "timer"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "websocket_server"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -33,7 +33,9 @@ Ubuntu under WSL, you can should install the Ubuntu dependencies listed in the [
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Dependencies (Ubuntu)
|
||||
### Dependencies
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
Several dependencies may be required to compile Lighthouse. The following
|
||||
packages may be required in addition a base Ubuntu Server installation:
|
||||
@@ -42,6 +44,12 @@ packages may be required in addition a base Ubuntu Server installation:
|
||||
sudo apt install -y git gcc g++ make cmake pkg-config libssl-dev
|
||||
```
|
||||
|
||||
#### macOS
|
||||
|
||||
You will need `cmake`. You can install via homebrew:
|
||||
|
||||
brew install cmake
|
||||
|
||||
### Command is not found
|
||||
|
||||
Lighthouse will be installed to `CARGO_HOME` or `$HOME/.cargo`. This directory
|
||||
|
||||
@@ -10,7 +10,7 @@ use target_info::Target;
|
||||
/// `Lighthouse/v0.2.0-1419501f2+`
|
||||
pub const VERSION: &str = git_version!(
|
||||
args = ["--always", "--dirty=+"],
|
||||
prefix = "Lighthouse/v0.2.0/",
|
||||
prefix = "Lighthouse/v0.2.1-",
|
||||
fallback = "unknown"
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "lcli"
|
||||
description = "Lighthouse CLI (modeled after zcli)"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -8,13 +8,15 @@ use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use types::{EnrForkId, EthSpec};
|
||||
use types::{ChainSpec, EnrForkId, Epoch, EthSpec, Hash256};
|
||||
|
||||
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
let ip: IpAddr = clap_utils::parse_required(matches, "ip")?;
|
||||
let udp_port: u16 = clap_utils::parse_required(matches, "udp-port")?;
|
||||
let tcp_port: u16 = clap_utils::parse_required(matches, "tcp-port")?;
|
||||
let output_dir: PathBuf = clap_utils::parse_required(matches, "output-dir")?;
|
||||
let genesis_fork_version: [u8; 4] =
|
||||
clap_utils::parse_ssz_required(matches, "genesis-fork-version")?;
|
||||
|
||||
if output_dir.exists() {
|
||||
return Err(format!(
|
||||
@@ -30,7 +32,12 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
|
||||
let local_keypair = Keypair::generate_secp256k1();
|
||||
let enr_key = CombinedKey::from_libp2p(&local_keypair)?;
|
||||
let enr = build_enr::<T>(&enr_key, &config, EnrForkId::default())
|
||||
let enr_fork_id = EnrForkId {
|
||||
fork_digest: ChainSpec::compute_fork_digest(genesis_fork_version, Hash256::zero()),
|
||||
next_fork_version: genesis_fork_version,
|
||||
next_fork_epoch: Epoch::max_value(), // FAR_FUTURE_EPOCH
|
||||
};
|
||||
let enr = build_enr::<T>(&enr_key, &config, enr_fork_id)
|
||||
.map_err(|e| format!("Unable to create ENR: {:?}", e))?;
|
||||
|
||||
fs::create_dir_all(&output_dir).map_err(|e| format!("Unable to create output-dir: {:?}", e))?;
|
||||
|
||||
@@ -440,6 +440,15 @@ fn main() {
|
||||
.required(true)
|
||||
.help("The directory in which to create the network dir"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("genesis-fork-version")
|
||||
.long("genesis-fork-version")
|
||||
.value_name("HEX")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("Used to avoid reply attacks between testnets. Recommended to set to
|
||||
non-default."),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("insecure-validators")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "lighthouse"
|
||||
version = "0.1.2"
|
||||
version = "0.2.1"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ fn bls_library_name() -> &'static str {
|
||||
fn main() {
|
||||
// Parse the CLI parameters.
|
||||
let matches = App::new("Lighthouse")
|
||||
.version(VERSION)
|
||||
.version(VERSION.replace("Lighthouse/", "").as_str())
|
||||
.author("Sigma Prime <contact@sigmaprime.io>")
|
||||
.setting(clap::AppSettings::ColoredHelp)
|
||||
.about(
|
||||
@@ -37,7 +37,7 @@ fn main() {
|
||||
format!(
|
||||
"{}\n\
|
||||
BLS Library: {}",
|
||||
VERSION, bls_library_name()
|
||||
VERSION.replace("Lighthouse/", ""), bls_library_name()
|
||||
).as_str()
|
||||
)
|
||||
.arg(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "validator_client"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>", "Luke Anderson <luke@lukeanderson.com.au>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
Arg::with_name("strict-lockfiles")
|
||||
.long("strict-lockfiles")
|
||||
.help(
|
||||
"If present, do not load validators that have are guarded by a lockfile. Note: for \
|
||||
"If present, do not load validators that are guarded by a lockfile. Note: for \
|
||||
Eth2 mainnet, this flag will likely be removed and its behaviour will become default."
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user