mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-29 20:27:14 +00:00
Merge remote-tracking branch 'origin/unstable' into tree-states
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
name = "cached_tree_hash"
|
||||
version = "0.1.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.12.1"
|
||||
|
||||
@@ -127,7 +127,7 @@ impl<T: Encode + Decode> CacheArena<T> {
|
||||
.offsets
|
||||
.get(alloc_id + 1)
|
||||
.copied()
|
||||
.unwrap_or_else(|| self.backing.len());
|
||||
.unwrap_or(self.backing.len());
|
||||
|
||||
Ok(end - start)
|
||||
}
|
||||
@@ -168,7 +168,7 @@ impl<T: Encode + Decode> CacheArena<T> {
|
||||
.offsets
|
||||
.get(alloc_id + 1)
|
||||
.copied()
|
||||
.unwrap_or_else(|| self.backing.len());
|
||||
.unwrap_or(self.backing.len());
|
||||
|
||||
Ok(start..end)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "fork_choice"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
use types::{
|
||||
consts::merge::INTERVALS_PER_SLOT, AttestationShufflingId, BeaconBlock, BeaconState,
|
||||
BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, IndexedAttestation,
|
||||
RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||
IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -17,6 +17,7 @@ pub enum Error<T> {
|
||||
ProtoArrayError(String),
|
||||
InvalidProtoArrayBytes(String),
|
||||
InvalidLegacyProtoArrayBytes(String),
|
||||
FailedToProcessInvalidExecutionPayload(String),
|
||||
MissingProtoArrayBlock(Hash256),
|
||||
UnknownAncestor {
|
||||
ancestor_slot: Slot,
|
||||
@@ -43,6 +44,12 @@ pub enum Error<T> {
|
||||
block_root: Hash256,
|
||||
payload_verification_status: PayloadVerificationStatus,
|
||||
},
|
||||
MissingJustifiedBlock {
|
||||
justified_checkpoint: Checkpoint,
|
||||
},
|
||||
MissingFinalizedBlock {
|
||||
finalized_checkpoint: Checkpoint,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> From<InvalidAttestation> for Error<T> {
|
||||
@@ -219,7 +226,7 @@ fn dequeue_attestations(
|
||||
queued_attestations
|
||||
.iter()
|
||||
.position(|a| a.slot >= current_slot)
|
||||
.unwrap_or_else(|| queued_attestations.len()),
|
||||
.unwrap_or(queued_attestations.len()),
|
||||
);
|
||||
|
||||
std::mem::replace(queued_attestations, remaining)
|
||||
@@ -299,9 +306,15 @@ where
|
||||
let execution_status = anchor_block.message_merge().map_or_else(
|
||||
|()| ExecutionStatus::irrelevant(),
|
||||
|message| {
|
||||
// Assume that this payload is valid, since the anchor should be a trusted block and
|
||||
// state.
|
||||
ExecutionStatus::Valid(message.body.execution_payload.block_hash)
|
||||
let execution_payload = &message.body.execution_payload;
|
||||
if execution_payload == &<_>::default() {
|
||||
// A default payload does not have execution enabled.
|
||||
ExecutionStatus::irrelevant()
|
||||
} else {
|
||||
// Assume that this payload is valid, since the anchor should be a trusted block and
|
||||
// state.
|
||||
ExecutionStatus::Valid(message.body.execution_payload.block_hash)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -467,6 +480,17 @@ where
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// See `ProtoArrayForkChoice::process_execution_payload_invalidation` for documentation.
|
||||
pub fn on_invalid_execution_payload(
|
||||
&mut self,
|
||||
head_block_root: Hash256,
|
||||
latest_valid_ancestor_root: Option<ExecutionBlockHash>,
|
||||
) -> Result<(), Error<T::Error>> {
|
||||
self.proto_array
|
||||
.process_execution_payload_invalidation(head_block_root, latest_valid_ancestor_root)
|
||||
.map_err(Error::FailedToProcessInvalidExecutionPayload)
|
||||
}
|
||||
|
||||
/// Add `block` to the fork choice DAG.
|
||||
///
|
||||
/// - `block_root` is the root of `block.
|
||||
@@ -595,7 +619,7 @@ where
|
||||
let execution_status = if let Ok(execution_payload) = block.body().execution_payload() {
|
||||
let block_hash = execution_payload.block_hash;
|
||||
|
||||
if block_hash == Hash256::zero() {
|
||||
if block_hash == ExecutionBlockHash::zero() {
|
||||
// The block is post-merge-fork, but pre-terminal-PoW block. We don't need to verify
|
||||
// the payload.
|
||||
ExecutionStatus::irrelevant()
|
||||
@@ -878,6 +902,29 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `ProtoBlock` for the justified checkpoint.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// This does *not* return the "best justified checkpoint". It returns the justified checkpoint
|
||||
/// that is used for computing balances.
|
||||
pub fn get_justified_block(&self) -> Result<ProtoBlock, Error<T::Error>> {
|
||||
let justified_checkpoint = self.justified_checkpoint();
|
||||
self.get_block(&justified_checkpoint.root)
|
||||
.ok_or(Error::MissingJustifiedBlock {
|
||||
justified_checkpoint,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the `ProtoBlock` for the finalized checkpoint.
|
||||
pub fn get_finalized_block(&self) -> Result<ProtoBlock, Error<T::Error>> {
|
||||
let finalized_checkpoint = self.finalized_checkpoint();
|
||||
self.get_block(&finalized_checkpoint.root)
|
||||
.ok_or(Error::MissingFinalizedBlock {
|
||||
finalized_checkpoint,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if `block_root` is equal to the finalized root, or a known descendant of it.
|
||||
pub fn is_descendant_of_finalized(&self, block_root: Hash256) -> bool {
|
||||
self.proto_array
|
||||
|
||||
@@ -122,18 +122,24 @@ impl ForkChoiceTest {
|
||||
}
|
||||
|
||||
/// Assert there was a shutdown signal sent by the beacon chain.
|
||||
pub fn assert_shutdown_signal_sent(mut self) -> Self {
|
||||
self.harness.shutdown_receiver.close();
|
||||
let msg = self.harness.shutdown_receiver.try_next().unwrap();
|
||||
assert!(msg.is_some());
|
||||
pub fn shutdown_signal_sent(&self) -> bool {
|
||||
let mutex = self.harness.shutdown_receiver.clone();
|
||||
let mut shutdown_receiver = mutex.lock();
|
||||
|
||||
shutdown_receiver.close();
|
||||
let msg = shutdown_receiver.try_next().unwrap();
|
||||
msg.is_some()
|
||||
}
|
||||
|
||||
/// Assert there was a shutdown signal sent by the beacon chain.
|
||||
pub fn assert_shutdown_signal_sent(self) -> Self {
|
||||
assert!(self.shutdown_signal_sent());
|
||||
self
|
||||
}
|
||||
|
||||
/// Assert no shutdown was signal sent by the beacon chain.
|
||||
pub fn assert_shutdown_signal_not_sent(mut self) -> Self {
|
||||
self.harness.shutdown_receiver.close();
|
||||
let msg = self.harness.shutdown_receiver.try_next().unwrap();
|
||||
assert!(msg.is_none());
|
||||
pub fn assert_shutdown_signal_not_sent(self) -> Self {
|
||||
assert!(!self.shutdown_signal_sent());
|
||||
self
|
||||
}
|
||||
|
||||
@@ -479,6 +485,22 @@ fn is_safe_to_update(slot: Slot, spec: &ChainSpec) -> bool {
|
||||
slot % E::slots_per_epoch() < spec.safe_slots_to_update_justified
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn justified_and_finalized_blocks() {
|
||||
let tester = ForkChoiceTest::new();
|
||||
let fork_choice = tester.harness.chain.fork_choice.read();
|
||||
|
||||
let justified_checkpoint = fork_choice.justified_checkpoint();
|
||||
assert_eq!(justified_checkpoint.epoch, 0);
|
||||
assert!(justified_checkpoint.root != Hash256::zero());
|
||||
assert!(fork_choice.get_justified_block().is_ok());
|
||||
|
||||
let finalized_checkpoint = fork_choice.finalized_checkpoint();
|
||||
assert_eq!(finalized_checkpoint.epoch, 0);
|
||||
assert!(finalized_checkpoint.root != Hash256::zero());
|
||||
assert!(fork_choice.get_finalized_block().is_ok());
|
||||
}
|
||||
|
||||
/// - The new justified checkpoint descends from the current.
|
||||
/// - Current slot is within `SAFE_SLOTS_TO_UPDATE_JUSTIFIED`
|
||||
#[test]
|
||||
@@ -613,7 +635,7 @@ fn justified_balances() {
|
||||
}
|
||||
|
||||
macro_rules! assert_invalid_block {
|
||||
($err: tt, $($error: pat) |+ $( if $guard: expr )?) => {
|
||||
($err: tt, $($error: pat_param) |+ $( if $guard: expr )?) => {
|
||||
assert!(
|
||||
matches!(
|
||||
$err,
|
||||
@@ -719,7 +741,7 @@ fn invalid_block_finalized_descendant() {
|
||||
}
|
||||
|
||||
macro_rules! assert_invalid_attestation {
|
||||
($err: tt, $($error: pat) |+ $( if $guard: expr )?) => {
|
||||
($err: tt, $($error: pat_param) |+ $( if $guard: expr )?) => {
|
||||
assert!(
|
||||
matches!(
|
||||
$err,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "int_to_bytes"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.0.1"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "merkle_proof"
|
||||
version = "0.2.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.12.1"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "proto_array"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "proto_array"
|
||||
|
||||
@@ -6,6 +6,18 @@ fn main() {
|
||||
write_test_def_to_yaml("no_votes.yaml", get_no_votes_test_definition());
|
||||
write_test_def_to_yaml("ffg_01.yaml", get_ffg_case_01_test_definition());
|
||||
write_test_def_to_yaml("ffg_02.yaml", get_ffg_case_02_test_definition());
|
||||
write_test_def_to_yaml(
|
||||
"execution_status_01.yaml",
|
||||
get_execution_status_test_definition_01(),
|
||||
);
|
||||
write_test_def_to_yaml(
|
||||
"execution_status_02.yaml",
|
||||
get_execution_status_test_definition_02(),
|
||||
);
|
||||
write_test_def_to_yaml(
|
||||
"execution_status_03.yaml",
|
||||
get_execution_status_test_definition_03(),
|
||||
);
|
||||
}
|
||||
|
||||
fn write_test_def_to_yaml(filename: &str, def: ForkChoiceTestDefinition) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use types::{Checkpoint, Epoch, Hash256};
|
||||
use types::{Checkpoint, Epoch, ExecutionBlockHash, Hash256};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Error {
|
||||
FinalizedNodeUnknown(Hash256),
|
||||
JustifiedNodeUnknown(Hash256),
|
||||
NodeUnknown(Hash256),
|
||||
InvalidFinalizedRootChange,
|
||||
InvalidNodeIndex(usize),
|
||||
InvalidParentIndex(usize),
|
||||
@@ -15,6 +16,7 @@ pub enum Error {
|
||||
DeltaOverflow(usize),
|
||||
ProposerBoostOverflow(usize),
|
||||
IndexOverflow(&'static str),
|
||||
InvalidExecutionDeltaOverflow(usize),
|
||||
InvalidDeltaLen {
|
||||
deltas: usize,
|
||||
indices: usize,
|
||||
@@ -26,7 +28,21 @@ pub enum Error {
|
||||
InvalidBestNode(Box<InvalidBestNodeInfo>),
|
||||
InvalidAncestorOfValidPayload {
|
||||
ancestor_block_root: Hash256,
|
||||
ancestor_payload_block_hash: Hash256,
|
||||
ancestor_payload_block_hash: ExecutionBlockHash,
|
||||
},
|
||||
ValidExecutionStatusBecameInvalid {
|
||||
block_root: Hash256,
|
||||
payload_block_hash: ExecutionBlockHash,
|
||||
},
|
||||
InvalidJustifiedCheckpointExecutionStatus {
|
||||
justified_root: Hash256,
|
||||
},
|
||||
UnknownLatestValidAncestorHash {
|
||||
block_root: Hash256,
|
||||
latest_valid_ancestor_hash: Option<ExecutionBlockHash>,
|
||||
},
|
||||
IrrelevantDescendant {
|
||||
block_root: Hash256,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
mod execution_status;
|
||||
mod ffg_updates;
|
||||
mod no_votes;
|
||||
mod votes;
|
||||
|
||||
use crate::proto_array_fork_choice::{Block, ExecutionStatus, ProtoArrayForkChoice};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use types::{AttestationShufflingId, Checkpoint, Epoch, EthSpec, Hash256, MainnetEthSpec, Slot};
|
||||
use types::{
|
||||
AttestationShufflingId, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||
MainnetEthSpec, Slot,
|
||||
};
|
||||
|
||||
pub use execution_status::*;
|
||||
pub use ffg_updates::*;
|
||||
pub use no_votes::*;
|
||||
pub use votes::*;
|
||||
@@ -18,6 +23,13 @@ pub enum Operation {
|
||||
justified_state_balances: Vec<u64>,
|
||||
expected_head: Hash256,
|
||||
},
|
||||
ProposerBoostFindHead {
|
||||
justified_checkpoint: Checkpoint,
|
||||
finalized_checkpoint: Checkpoint,
|
||||
justified_state_balances: Vec<u64>,
|
||||
expected_head: Hash256,
|
||||
proposer_boost_root: Hash256,
|
||||
},
|
||||
InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint,
|
||||
finalized_checkpoint: Checkpoint,
|
||||
@@ -40,6 +52,14 @@ pub enum Operation {
|
||||
prune_threshold: usize,
|
||||
expected_len: usize,
|
||||
},
|
||||
InvalidatePayload {
|
||||
head_block_root: Hash256,
|
||||
latest_valid_ancestor_root: Option<ExecutionBlockHash>,
|
||||
},
|
||||
AssertWeight {
|
||||
block_root: Hash256,
|
||||
weight: u64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -52,9 +72,11 @@ pub struct ForkChoiceTestDefinition {
|
||||
|
||||
impl ForkChoiceTestDefinition {
|
||||
pub fn run(self) {
|
||||
let mut spec = MainnetEthSpec::default_spec();
|
||||
spec.proposer_score_boost = Some(50);
|
||||
|
||||
let junk_shuffling_id =
|
||||
AttestationShufflingId::from_components(Epoch::new(0), Hash256::zero());
|
||||
let execution_status = ExecutionStatus::irrelevant();
|
||||
let mut fork_choice = ProtoArrayForkChoice::new(
|
||||
self.finalized_block_slot,
|
||||
Hash256::zero(),
|
||||
@@ -62,7 +84,7 @@ impl ForkChoiceTestDefinition {
|
||||
self.finalized_checkpoint,
|
||||
junk_shuffling_id.clone(),
|
||||
junk_shuffling_id,
|
||||
execution_status,
|
||||
ExecutionStatus::Unknown(ExecutionBlockHash::zero()),
|
||||
)
|
||||
.expect("should create fork choice struct");
|
||||
|
||||
@@ -80,7 +102,7 @@ impl ForkChoiceTestDefinition {
|
||||
finalized_checkpoint,
|
||||
&justified_state_balances,
|
||||
Hash256::zero(),
|
||||
&MainnetEthSpec::default_spec(),
|
||||
&spec,
|
||||
)
|
||||
.map_err(|e| e)
|
||||
.unwrap_or_else(|e| {
|
||||
@@ -89,7 +111,34 @@ impl ForkChoiceTestDefinition {
|
||||
|
||||
assert_eq!(
|
||||
head, expected_head,
|
||||
"Operation at index {} failed checks. Operation: {:?}",
|
||||
"Operation at index {} failed head check. Operation: {:?}",
|
||||
op_index, op
|
||||
);
|
||||
check_bytes_round_trip(&fork_choice);
|
||||
}
|
||||
Operation::ProposerBoostFindHead {
|
||||
justified_checkpoint,
|
||||
finalized_checkpoint,
|
||||
justified_state_balances,
|
||||
expected_head,
|
||||
proposer_boost_root,
|
||||
} => {
|
||||
let head = fork_choice
|
||||
.find_head::<MainnetEthSpec>(
|
||||
justified_checkpoint,
|
||||
finalized_checkpoint,
|
||||
&justified_state_balances,
|
||||
proposer_boost_root,
|
||||
&spec,
|
||||
)
|
||||
.map_err(|e| e)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("find_head op at index {} returned error {}", op_index, e)
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
head, expected_head,
|
||||
"Operation at index {} failed head check. Operation: {:?}",
|
||||
op_index, op
|
||||
);
|
||||
check_bytes_round_trip(&fork_choice);
|
||||
@@ -104,7 +153,7 @@ impl ForkChoiceTestDefinition {
|
||||
finalized_checkpoint,
|
||||
&justified_state_balances,
|
||||
Hash256::zero(),
|
||||
&MainnetEthSpec::default_spec(),
|
||||
&spec,
|
||||
);
|
||||
|
||||
assert!(
|
||||
@@ -138,7 +187,10 @@ impl ForkChoiceTestDefinition {
|
||||
),
|
||||
justified_checkpoint,
|
||||
finalized_checkpoint,
|
||||
execution_status,
|
||||
// All blocks are imported optimistically.
|
||||
execution_status: ExecutionStatus::Unknown(ExecutionBlockHash::from_root(
|
||||
root,
|
||||
)),
|
||||
};
|
||||
fork_choice.process_block(block).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
@@ -183,22 +235,41 @@ impl ForkChoiceTestDefinition {
|
||||
expected_len
|
||||
);
|
||||
}
|
||||
Operation::InvalidatePayload {
|
||||
head_block_root,
|
||||
latest_valid_ancestor_root,
|
||||
} => fork_choice
|
||||
.process_execution_payload_invalidation(
|
||||
head_block_root,
|
||||
latest_valid_ancestor_root,
|
||||
)
|
||||
.unwrap(),
|
||||
Operation::AssertWeight { block_root, weight } => assert_eq!(
|
||||
fork_choice.get_weight(&block_root).unwrap(),
|
||||
weight,
|
||||
"block weight"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gives a hash that is not the zero hash (unless i is `usize::max_value)`.
|
||||
fn get_hash(i: u64) -> Hash256 {
|
||||
/// Gives a root that is not the zero hash (unless i is `usize::max_value)`.
|
||||
fn get_root(i: u64) -> Hash256 {
|
||||
Hash256::from_low_u64_be(i + 1)
|
||||
}
|
||||
|
||||
/// Gives a hash that is not the zero hash (unless i is `usize::max_value)`.
|
||||
fn get_hash(i: u64) -> ExecutionBlockHash {
|
||||
ExecutionBlockHash::from_root(get_root(i))
|
||||
}
|
||||
|
||||
/// Gives a checkpoint with a root that is not the zero hash (unless i is `usize::max_value)`.
|
||||
/// `Epoch` will always equal `i`.
|
||||
fn get_checkpoint(i: u64) -> Checkpoint {
|
||||
Checkpoint {
|
||||
epoch: Epoch::new(i),
|
||||
root: get_hash(i),
|
||||
root: get_root(i),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(0),
|
||||
expected_head: get_root(0),
|
||||
});
|
||||
|
||||
// Build the following tree (stick? lol).
|
||||
@@ -23,22 +23,22 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 3 <- just: 2, fin: 1
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(1),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(2),
|
||||
parent_root: get_hash(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(1),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_hash(3),
|
||||
parent_root: get_hash(2),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(2),
|
||||
finalized_checkpoint: get_checkpoint(1),
|
||||
});
|
||||
@@ -56,7 +56,7 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(3),
|
||||
expected_head: get_root(3),
|
||||
});
|
||||
|
||||
// Ensure that with justified epoch 1 we find 2
|
||||
@@ -72,7 +72,7 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(1),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Ensure that with justified epoch 2 we find 3
|
||||
@@ -88,7 +88,7 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(2),
|
||||
finalized_checkpoint: get_checkpoint(1),
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_hash(3),
|
||||
expected_head: get_root(3),
|
||||
});
|
||||
|
||||
// END OF TESTS
|
||||
@@ -109,7 +109,7 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(0),
|
||||
expected_head: get_root(0),
|
||||
});
|
||||
|
||||
// Build the following tree.
|
||||
@@ -129,48 +129,48 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
// Left branch
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(1),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(3),
|
||||
parent_root: get_hash(1),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_hash(5),
|
||||
parent_root: get_hash(3),
|
||||
root: get_root(5),
|
||||
parent_root: get_root(3),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
root: get_hash(7),
|
||||
parent_root: get_hash(5),
|
||||
root: get_root(7),
|
||||
parent_root: get_root(5),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(5),
|
||||
root: get_hash(9),
|
||||
parent_root: get_hash(7),
|
||||
root: get_root(9),
|
||||
parent_root: get_root(7),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(3),
|
||||
root: get_root(3),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
@@ -178,42 +178,42 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
// Right branch
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(2),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(4),
|
||||
parent_root: get_hash(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_hash(6),
|
||||
parent_root: get_hash(4),
|
||||
root: get_root(6),
|
||||
parent_root: get_root(4),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
root: get_hash(8),
|
||||
parent_root: get_hash(6),
|
||||
root: get_root(8),
|
||||
parent_root: get_root(6),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(2),
|
||||
root: get_root(2),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(5),
|
||||
root: get_hash(10),
|
||||
parent_root: get_hash(8),
|
||||
root: get_root(10),
|
||||
parent_root: get_root(8),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(4),
|
||||
root: get_root(4),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
});
|
||||
@@ -235,23 +235,23 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above, but with justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(4),
|
||||
root: get_root(4),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above, but with justified epoch 3 (should be invalid).
|
||||
ops.push(Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(3),
|
||||
root: get_hash(6),
|
||||
root: get_root(6),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
@@ -272,7 +272,7 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9 10
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_hash(1),
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(0),
|
||||
});
|
||||
|
||||
@@ -293,23 +293,23 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
// Save as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(3),
|
||||
root: get_root(3),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
// Save as above but justified epoch 3 (should fail).
|
||||
ops.push(Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(3),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
@@ -330,7 +330,7 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9 10
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_hash(2),
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(0),
|
||||
});
|
||||
|
||||
@@ -351,23 +351,23 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(4),
|
||||
root: get_root(4),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above but justified epoch 3 (should fail).
|
||||
ops.push(Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(3),
|
||||
root: get_hash(6),
|
||||
root: get_root(6),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
@@ -389,27 +389,27 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(0),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(3),
|
||||
root: get_root(3),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
// Same as above but justified epoch 3 (should fail).
|
||||
ops.push(Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(3),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
@@ -432,23 +432,23 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(4),
|
||||
root: get_root(4),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
// Same as above but justified epoch 3 (should fail).
|
||||
ops.push(Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(3),
|
||||
root: get_hash(6),
|
||||
root: get_root(6),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances,
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 2
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(2),
|
||||
root: get_root(2),
|
||||
parent_root: Hash256::zero(),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
@@ -50,7 +50,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
},
|
||||
// Add block 1
|
||||
//
|
||||
@@ -59,8 +59,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 2 1
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(1),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
@@ -85,7 +85,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
},
|
||||
// Add block 3
|
||||
//
|
||||
@@ -96,8 +96,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 3
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(3),
|
||||
parent_root: get_hash(1),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
@@ -124,7 +124,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
},
|
||||
// Add block 4
|
||||
//
|
||||
@@ -135,8 +135,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 4 3
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(4),
|
||||
parent_root: get_hash(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
@@ -163,7 +163,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(4),
|
||||
expected_head: get_root(4),
|
||||
},
|
||||
// Add block 5 with a justified epoch of 2
|
||||
//
|
||||
@@ -176,8 +176,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 5 <- justified epoch = 2
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_hash(5),
|
||||
parent_root: get_hash(4),
|
||||
root: get_root(5),
|
||||
parent_root: get_root(4),
|
||||
justified_checkpoint: get_checkpoint(2),
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
@@ -203,7 +203,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(4),
|
||||
expected_head: get_root(4),
|
||||
},
|
||||
// Ensure there is an error when starting from a block that has the wrong justified epoch.
|
||||
//
|
||||
@@ -217,7 +217,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
Operation::InvalidFindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
@@ -241,7 +241,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(5),
|
||||
expected_head: get_root(5),
|
||||
},
|
||||
// Add block 6
|
||||
//
|
||||
@@ -256,8 +256,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 6
|
||||
Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
root: get_hash(6),
|
||||
parent_root: get_hash(5),
|
||||
root: get_root(6),
|
||||
parent_root: get_root(5),
|
||||
justified_checkpoint: get_checkpoint(2),
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
@@ -282,7 +282,7 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_hash(6),
|
||||
expected_head: get_root(6),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(0),
|
||||
expected_head: get_root(0),
|
||||
});
|
||||
|
||||
// Add a block with a hash of 2.
|
||||
@@ -25,15 +25,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 2
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(2),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -45,14 +45,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Add a block with a hash of 1 that comes off the genesis block (this is a fork compared
|
||||
@@ -63,15 +63,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 2 1
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_hash(1),
|
||||
parent_root: get_hash(0),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -83,14 +83,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Add a vote to block 1
|
||||
@@ -100,7 +100,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 2 1 <- +vote
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_hash(1),
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
});
|
||||
|
||||
@@ -112,14 +112,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(1),
|
||||
expected_head: get_root(1),
|
||||
});
|
||||
|
||||
// Add a vote to block 2
|
||||
@@ -129,7 +129,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// +vote-> 2 1
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_hash(2),
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(2),
|
||||
});
|
||||
|
||||
@@ -141,14 +141,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Add block 3.
|
||||
@@ -160,15 +160,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 3
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_hash(3),
|
||||
parent_root: get_hash(1),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -182,14 +182,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Move validator #0 vote from 1 to 3
|
||||
@@ -201,7 +201,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 3 <- +vote
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_hash(3),
|
||||
block_root: get_root(3),
|
||||
target_epoch: Epoch::new(3),
|
||||
});
|
||||
|
||||
@@ -215,14 +215,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(2),
|
||||
expected_head: get_root(2),
|
||||
});
|
||||
|
||||
// Move validator #1 vote from 2 to 1 (this is an equivocation, but fork choice doesn't
|
||||
@@ -235,7 +235,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 3
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_hash(1),
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(3),
|
||||
});
|
||||
|
||||
@@ -249,14 +249,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(3),
|
||||
expected_head: get_root(3),
|
||||
});
|
||||
|
||||
// Add block 4.
|
||||
@@ -270,15 +270,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 4
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_hash(4),
|
||||
parent_root: get_hash(3),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(3),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -294,14 +294,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(4),
|
||||
expected_head: get_root(4),
|
||||
});
|
||||
|
||||
// Add block 5, which has a justified epoch of 2.
|
||||
@@ -317,15 +317,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 5 <- justified epoch = 2
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
root: get_hash(5),
|
||||
parent_root: get_hash(4),
|
||||
root: get_root(5),
|
||||
parent_root: get_root(4),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(1),
|
||||
root: get_root(1),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -343,14 +343,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(4),
|
||||
expected_head: get_root(4),
|
||||
});
|
||||
|
||||
// Add block 6, which has a justified epoch of 0.
|
||||
@@ -366,15 +366,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 5 6 <- justified epoch = 0
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(6),
|
||||
parent_root: get_hash(4),
|
||||
root: get_root(6),
|
||||
parent_root: get_root(4),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -391,12 +391,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// +2 vote-> 5 6
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_hash(5),
|
||||
block_root: get_root(5),
|
||||
target_epoch: Epoch::new(4),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_hash(5),
|
||||
block_root: get_root(5),
|
||||
target_epoch: Epoch::new(4),
|
||||
});
|
||||
|
||||
@@ -420,41 +420,41 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(7),
|
||||
parent_root: get_hash(5),
|
||||
root: get_root(7),
|
||||
parent_root: get_root(5),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(8),
|
||||
parent_root: get_hash(7),
|
||||
root: get_root(8),
|
||||
parent_root: get_root(7),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(9),
|
||||
parent_root: get_hash(8),
|
||||
root: get_root(9),
|
||||
parent_root: get_root(8),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -479,14 +479,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(6),
|
||||
expected_head: get_root(6),
|
||||
});
|
||||
|
||||
// Change fork-choice justified epoch to 1, and the start block to 5 and ensure that 9 is
|
||||
@@ -512,14 +512,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Change fork-choice justified epoch to 1, and the start block to 5 and ensure that 9 is
|
||||
@@ -544,12 +544,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9 <- +2 votes
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_hash(9),
|
||||
block_root: get_root(9),
|
||||
target_epoch: Epoch::new(5),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_hash(9),
|
||||
block_root: get_root(9),
|
||||
target_epoch: Epoch::new(5),
|
||||
});
|
||||
|
||||
@@ -572,15 +572,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9 10
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(10),
|
||||
parent_root: get_hash(8),
|
||||
root: get_root(10),
|
||||
parent_root: get_root(8),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -588,14 +588,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Introduce 2 more validators into the system
|
||||
@@ -620,12 +620,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 9 10 <- +2 votes
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 2,
|
||||
block_root: get_hash(10),
|
||||
block_root: get_root(10),
|
||||
target_epoch: Epoch::new(5),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 3,
|
||||
block_root: get_hash(10),
|
||||
block_root: get_root(10),
|
||||
target_epoch: Epoch::new(5),
|
||||
});
|
||||
|
||||
@@ -649,14 +649,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
|
||||
// Set the balances of the last two validators to zero
|
||||
@@ -674,14 +674,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Set the balances of the last two validators back to 1
|
||||
@@ -699,14 +699,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(10),
|
||||
expected_head: get_root(10),
|
||||
});
|
||||
|
||||
// Remove the last two validators
|
||||
@@ -725,19 +725,19 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Ensure that pruning below the prune threshold does not prune.
|
||||
ops.push(Operation::Prune {
|
||||
finalized_root: get_hash(5),
|
||||
finalized_root: get_root(5),
|
||||
prune_threshold: usize::max_value(),
|
||||
expected_len: 11,
|
||||
});
|
||||
@@ -746,14 +746,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Ensure that pruning above the prune threshold does prune.
|
||||
@@ -775,7 +775,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// / \
|
||||
// 9 10
|
||||
ops.push(Operation::Prune {
|
||||
finalized_root: get_hash(5),
|
||||
finalized_root: get_root(5),
|
||||
prune_threshold: 1,
|
||||
expected_len: 6,
|
||||
});
|
||||
@@ -784,14 +784,14 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_hash(9),
|
||||
expected_head: get_root(9),
|
||||
});
|
||||
|
||||
// Add block 11
|
||||
@@ -807,15 +807,15 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
// 11
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
root: get_hash(11),
|
||||
parent_root: get_hash(9),
|
||||
root: get_root(11),
|
||||
parent_root: get_root(9),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -833,25 +833,25 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_hash(5),
|
||||
root: get_root(5),
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_hash(11),
|
||||
expected_head: get_root(11),
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
finalized_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_hash(0),
|
||||
root: get_root(0),
|
||||
},
|
||||
operations: ops,
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::four_byte_option_impl;
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::collections::HashMap;
|
||||
use types::{AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, Slot};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use types::{
|
||||
AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||
Slot,
|
||||
};
|
||||
|
||||
// Define a "legacy" implementation of `Option<usize>` which uses four bytes for encoding the union
|
||||
// selector.
|
||||
@@ -126,26 +129,42 @@ impl ProtoArray {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut node_delta = deltas
|
||||
.get(node_index)
|
||||
.copied()
|
||||
.ok_or(Error::InvalidNodeDelta(node_index))?;
|
||||
let execution_status_is_invalid = node.execution_status.is_invalid();
|
||||
|
||||
let mut node_delta = if execution_status_is_invalid {
|
||||
// If the node has an invalid execution payload, reduce its weight to zero.
|
||||
0_i64
|
||||
.checked_sub(node.weight as i64)
|
||||
.ok_or(Error::InvalidExecutionDeltaOverflow(node_index))?
|
||||
} else {
|
||||
deltas
|
||||
.get(node_index)
|
||||
.copied()
|
||||
.ok_or(Error::InvalidNodeDelta(node_index))?
|
||||
};
|
||||
|
||||
// If we find the node for which the proposer boost was previously applied, decrease
|
||||
// the delta by the previous score amount.
|
||||
if self.previous_proposer_boost.root != Hash256::zero()
|
||||
&& self.previous_proposer_boost.root == node.root
|
||||
// Invalid nodes will always have a weight of zero so there's no need to subtract
|
||||
// the proposer boost delta.
|
||||
&& !execution_status_is_invalid
|
||||
{
|
||||
node_delta = node_delta
|
||||
.checked_sub(self.previous_proposer_boost.score as i64)
|
||||
.ok_or(Error::DeltaOverflow(node_index))?;
|
||||
}
|
||||
// If we find the node matching the current proposer boost root, increase
|
||||
// the delta by the new score amount.
|
||||
// the delta by the new score amount (unless the block has an invalid execution status).
|
||||
//
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/fork-choice.md#get_latest_attesting_balance
|
||||
if let Some(proposer_score_boost) = spec.proposer_score_boost {
|
||||
if proposer_boost_root != Hash256::zero() && proposer_boost_root == node.root {
|
||||
if proposer_boost_root != Hash256::zero()
|
||||
&& proposer_boost_root == node.root
|
||||
// Invalid nodes (or their ancestors) should not receive a proposer boost.
|
||||
&& !execution_status_is_invalid
|
||||
{
|
||||
proposer_score =
|
||||
calculate_proposer_boost::<E>(new_balances, proposer_score_boost)
|
||||
.ok_or(Error::ProposerBoostOverflow(node_index))?;
|
||||
@@ -156,7 +175,10 @@ impl ProtoArray {
|
||||
}
|
||||
|
||||
// Apply the delta to the node.
|
||||
if node_delta < 0 {
|
||||
if execution_status_is_invalid {
|
||||
// Invalid nodes always have a weight of 0.
|
||||
node.weight = 0
|
||||
} else if node_delta < 0 {
|
||||
// Note: I am conflicted about whether to use `saturating_sub` or `checked_sub`
|
||||
// here.
|
||||
//
|
||||
@@ -250,14 +272,20 @@ impl ProtoArray {
|
||||
self.maybe_update_best_child_and_descendant(parent_index, node_index)?;
|
||||
|
||||
if matches!(block.execution_status, ExecutionStatus::Valid(_)) {
|
||||
self.propagate_execution_payload_verification(parent_index)?;
|
||||
self.propagate_execution_payload_validation(parent_index)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn propagate_execution_payload_verification(
|
||||
/// Updates the `verified_node_index` and all ancestors to have validated execution payloads.
|
||||
///
|
||||
/// Returns an error if:
|
||||
///
|
||||
/// - The `verified_node_index` is unknown.
|
||||
/// - Any of the to-be-validated payloads are already invalid.
|
||||
pub fn propagate_execution_payload_validation(
|
||||
&mut self,
|
||||
verified_node_index: usize,
|
||||
) -> Result<(), Error> {
|
||||
@@ -300,6 +328,213 @@ impl ProtoArray {
|
||||
}
|
||||
}
|
||||
|
||||
/// Invalidate the relevant ancestors and descendants of a block with an invalid execution
|
||||
/// payload.
|
||||
///
|
||||
/// The `head_block_root` should be the beacon block root of the block with the invalid
|
||||
/// execution payload, _or_ its parent where the block with the invalid payload has not yet
|
||||
/// been applied to `self`.
|
||||
///
|
||||
/// The `latest_valid_hash` should be the hash of most recent *valid* execution payload
|
||||
/// contained in an ancestor block of `head_block_root`.
|
||||
///
|
||||
/// This function will invalidate:
|
||||
///
|
||||
/// * The block matching `head_block_root` _unless_ that block has a payload matching `latest_valid_hash`.
|
||||
/// * All ancestors of `head_block_root` back to the block with payload matching
|
||||
/// `latest_valid_hash` (endpoint > exclusive). In the case where the `head_block_root` is the parent
|
||||
/// of the invalid block and itself matches `latest_valid_hash`, no ancestors will be invalidated.
|
||||
/// * All descendants of `latest_valid_hash` if supplied and consistent with `head_block_root`,
|
||||
/// or else all descendants of `head_block_root`.
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// If `head_block_root` is not known to fork choice, an error is returned.
|
||||
///
|
||||
/// If `latest_valid_hash` is `Some(hash)` where `hash` is either not known to fork choice
|
||||
/// (perhaps it's junk or pre-finalization), then only the `head_block_root` block will be
|
||||
/// invalidated (no ancestors). No error will be returned in this case.
|
||||
///
|
||||
/// If `latest_valid_hash` is `Some(hash)` where `hash` is a known ancestor of
|
||||
/// `head_block_root`, then all blocks between `head_block_root` and `latest_valid_hash` will
|
||||
/// be invalidated. Additionally, all blocks that descend from a newly-invalidated block will
|
||||
/// also be invalidated.
|
||||
pub fn propagate_execution_payload_invalidation(
|
||||
&mut self,
|
||||
head_block_root: Hash256,
|
||||
latest_valid_ancestor_hash: Option<ExecutionBlockHash>,
|
||||
) -> Result<(), Error> {
|
||||
let mut invalidated_indices: HashSet<usize> = <_>::default();
|
||||
|
||||
/*
|
||||
* Step 1:
|
||||
*
|
||||
* Find the `head_block_root` and maybe iterate backwards and invalidate ancestors. Record
|
||||
* all invalidated block indices in `invalidated_indices`.
|
||||
*/
|
||||
|
||||
let mut index = *self
|
||||
.indices
|
||||
.get(&head_block_root)
|
||||
.ok_or(Error::NodeUnknown(head_block_root))?;
|
||||
|
||||
// Try to map the ancestor payload *hash* to an ancestor beacon block *root*.
|
||||
let latest_valid_ancestor_root = latest_valid_ancestor_hash
|
||||
.and_then(|hash| self.execution_block_hash_to_beacon_block_root(&hash));
|
||||
|
||||
// Set to `true` if both conditions are satisfied:
|
||||
//
|
||||
// 1. The `head_block_root` is a descendant of `latest_valid_ancestor_hash`
|
||||
// 2. The `latest_valid_ancestor_hash` is equal to or a descendant of the finalized block.
|
||||
let latest_valid_ancestor_is_descendant =
|
||||
latest_valid_ancestor_root.map_or(false, |ancestor_root| {
|
||||
self.is_descendant(ancestor_root, head_block_root)
|
||||
&& self.is_descendant(self.finalized_checkpoint.root, ancestor_root)
|
||||
});
|
||||
|
||||
// Collect all *ancestors* which were declared invalid since they reside between the
|
||||
// `head_block_root` and the `latest_valid_ancestor_root`.
|
||||
loop {
|
||||
let node = self
|
||||
.nodes
|
||||
.get_mut(index)
|
||||
.ok_or(Error::InvalidNodeIndex(index))?;
|
||||
|
||||
match node.execution_status {
|
||||
ExecutionStatus::Valid(hash)
|
||||
| ExecutionStatus::Invalid(hash)
|
||||
| ExecutionStatus::Unknown(hash) => {
|
||||
// If we're no longer processing the `head_block_root` and the last valid
|
||||
// ancestor is unknown, exit this loop and proceed to invalidate and
|
||||
// descendants of `head_block_root`/`latest_valid_ancestor_root`.
|
||||
//
|
||||
// In effect, this means that if an unknown hash (junk or pre-finalization) is
|
||||
// supplied, don't validate any ancestors. The alternative is to invalidate
|
||||
// *all* ancestors, which would likely involve shutting down the client due to
|
||||
// an invalid justified checkpoint.
|
||||
if !latest_valid_ancestor_is_descendant && node.root != head_block_root {
|
||||
break;
|
||||
} else if Some(hash) == latest_valid_ancestor_hash {
|
||||
// If the `best_child` or `best_descendant` of the latest valid hash was
|
||||
// invalidated, set those fields to `None`.
|
||||
//
|
||||
// In theory, an invalid `best_child` necessarily infers an invalid
|
||||
// `best_descendant`. However, we check each variable independently to
|
||||
// defend against errors which might result in an invalid block being set as
|
||||
// head.
|
||||
if node
|
||||
.best_child
|
||||
.map_or(false, |i| invalidated_indices.contains(&i))
|
||||
{
|
||||
node.best_child = None
|
||||
}
|
||||
if node
|
||||
.best_descendant
|
||||
.map_or(false, |i| invalidated_indices.contains(&i))
|
||||
{
|
||||
node.best_descendant = None
|
||||
}
|
||||
|
||||
// It might be new knowledge that this block is valid, ensure that it and all
|
||||
// ancestors are marked as valid.
|
||||
self.propagate_execution_payload_validation(index)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ExecutionStatus::Irrelevant(_) => break,
|
||||
}
|
||||
|
||||
match &node.execution_status {
|
||||
// It's illegal for an execution client to declare that some previously-valid block
|
||||
// is now invalid. This is a consensus failure on their behalf.
|
||||
ExecutionStatus::Valid(hash) => {
|
||||
return Err(Error::ValidExecutionStatusBecameInvalid {
|
||||
block_root: node.root,
|
||||
payload_block_hash: *hash,
|
||||
})
|
||||
}
|
||||
ExecutionStatus::Unknown(hash) => {
|
||||
node.execution_status = ExecutionStatus::Invalid(*hash);
|
||||
|
||||
// It's impossible for an invalid block to lead to a "best" block, so set these
|
||||
// fields to `None`.
|
||||
//
|
||||
// Failing to set these values will result in `Self::node_leads_to_viable_head`
|
||||
// returning `false` for *valid* ancestors of invalid blocks.
|
||||
node.best_child = None;
|
||||
node.best_descendant = None;
|
||||
}
|
||||
// The block is already invalid, but keep going backwards to ensure all ancestors
|
||||
// are updated.
|
||||
ExecutionStatus::Invalid(_) => (),
|
||||
// This block is pre-merge, therefore it has no execution status. Nor do its
|
||||
// ancestors.
|
||||
ExecutionStatus::Irrelevant(_) => break,
|
||||
}
|
||||
|
||||
invalidated_indices.insert(index);
|
||||
|
||||
if let Some(parent_index) = node.parent {
|
||||
index = parent_index
|
||||
} else {
|
||||
// The root of the block tree has been reached (aka the finalized block), without
|
||||
// matching `latest_valid_ancestor_hash`. It's not possible or useful to go any
|
||||
// further back: the finalized checkpoint is invalid so all is lost!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2:
|
||||
*
|
||||
* Start at either the `latest_valid_ancestor` or the `head_block_root` and iterate
|
||||
* *forwards* to invalidate all descendants of all blocks in `invalidated_indices`.
|
||||
*/
|
||||
|
||||
let starting_block_root = latest_valid_ancestor_root
|
||||
.filter(|_| latest_valid_ancestor_is_descendant)
|
||||
.unwrap_or(head_block_root);
|
||||
let latest_valid_ancestor_index = *self
|
||||
.indices
|
||||
.get(&starting_block_root)
|
||||
.ok_or(Error::NodeUnknown(starting_block_root))?;
|
||||
let first_potential_descendant = latest_valid_ancestor_index + 1;
|
||||
|
||||
// Collect all *descendants* which have been declared invalid since they're the descendant of a block
|
||||
// with an invalid execution payload.
|
||||
for index in first_potential_descendant..self.nodes.len() {
|
||||
let node = self
|
||||
.nodes
|
||||
.get_mut(index)
|
||||
.ok_or(Error::InvalidNodeIndex(index))?;
|
||||
|
||||
if let Some(parent_index) = node.parent {
|
||||
if invalidated_indices.contains(&parent_index) {
|
||||
match &node.execution_status {
|
||||
ExecutionStatus::Valid(hash) => {
|
||||
return Err(Error::ValidExecutionStatusBecameInvalid {
|
||||
block_root: node.root,
|
||||
payload_block_hash: *hash,
|
||||
})
|
||||
}
|
||||
ExecutionStatus::Unknown(hash) | ExecutionStatus::Invalid(hash) => {
|
||||
node.execution_status = ExecutionStatus::Invalid(*hash)
|
||||
}
|
||||
ExecutionStatus::Irrelevant(_) => {
|
||||
return Err(Error::IrrelevantDescendant {
|
||||
block_root: node.root,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
invalidated_indices.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Follows the best-descendant links to find the best-block (i.e., head-block).
|
||||
///
|
||||
/// ## Notes
|
||||
@@ -313,13 +548,26 @@ impl ProtoArray {
|
||||
.indices
|
||||
.get(justified_root)
|
||||
.copied()
|
||||
.ok_or_else(|| Error::JustifiedNodeUnknown(*justified_root))?;
|
||||
.ok_or(Error::JustifiedNodeUnknown(*justified_root))?;
|
||||
|
||||
let justified_node = self
|
||||
.nodes
|
||||
.get(justified_index)
|
||||
.ok_or(Error::InvalidJustifiedIndex(justified_index))?;
|
||||
|
||||
// Since there are no valid descendants of a justified block with an invalid execution
|
||||
// payload, there would be no head to choose from.
|
||||
//
|
||||
// Fork choice is effectively broken until a new justified root is set. It might not be
|
||||
// practically possible to set a new justified root if we are unable to find a new head.
|
||||
//
|
||||
// This scenario is *unsupported*. It represents a serious consensus failure.
|
||||
if justified_node.execution_status.is_invalid() {
|
||||
return Err(Error::InvalidJustifiedCheckpointExecutionStatus {
|
||||
justified_root: *justified_root,
|
||||
});
|
||||
}
|
||||
|
||||
let best_descendant_index = justified_node.best_descendant.unwrap_or(justified_index);
|
||||
|
||||
let best_node = self
|
||||
@@ -537,6 +785,10 @@ impl ProtoArray {
|
||||
/// Any node that has a different finalized or justified epoch should not be viable for the
|
||||
/// head.
|
||||
fn node_is_viable_for_head(&self, node: &ProtoNode) -> bool {
|
||||
if node.execution_status.is_invalid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let (Some(node_justified_checkpoint), Some(node_finalized_checkpoint)) =
|
||||
(node.justified_checkpoint, node.finalized_checkpoint)
|
||||
{
|
||||
@@ -568,6 +820,42 @@ impl ProtoArray {
|
||||
self.iter_nodes(block_root)
|
||||
.map(|node| (node.root, node.slot))
|
||||
}
|
||||
|
||||
/// Returns `true` if the `descendant_root` has an ancestor with `ancestor_root`. Always
|
||||
/// returns `false` if either input root is unknown.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// Still returns `true` if `ancestor_root` is known and `ancestor_root == descendant_root`.
|
||||
pub fn is_descendant(&self, ancestor_root: Hash256, descendant_root: Hash256) -> bool {
|
||||
self.indices
|
||||
.get(&ancestor_root)
|
||||
.and_then(|ancestor_index| self.nodes.get(*ancestor_index))
|
||||
.and_then(|ancestor| {
|
||||
self.iter_block_roots(&descendant_root)
|
||||
.take_while(|(_root, slot)| *slot >= ancestor.slot)
|
||||
.find(|(_root, slot)| *slot == ancestor.slot)
|
||||
.map(|(root, _slot)| root == ancestor_root)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Returns the first *beacon block root* which contains an execution payload with the given
|
||||
/// `block_hash`, if any.
|
||||
pub fn execution_block_hash_to_beacon_block_root(
|
||||
&self,
|
||||
block_hash: &ExecutionBlockHash,
|
||||
) -> Option<Hash256> {
|
||||
self.nodes
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|node| {
|
||||
node.execution_status
|
||||
.block_hash()
|
||||
.map_or(false, |node_block_hash| node_block_hash == *block_hash)
|
||||
})
|
||||
.map(|node| node.root)
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper method to calculate the proposer boost based on the given `validator_balances`.
|
||||
|
||||
@@ -5,7 +5,10 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::collections::HashMap;
|
||||
use types::{AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, Slot};
|
||||
use types::{
|
||||
AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||
Slot,
|
||||
};
|
||||
|
||||
pub const DEFAULT_PRUNE_THRESHOLD: usize = 256;
|
||||
|
||||
@@ -21,11 +24,11 @@ pub struct VoteTracker {
|
||||
#[ssz(enum_behaviour = "union")]
|
||||
pub enum ExecutionStatus {
|
||||
/// An EL has determined that the payload is valid.
|
||||
Valid(Hash256),
|
||||
Valid(ExecutionBlockHash),
|
||||
/// An EL has determined that the payload is invalid.
|
||||
Invalid(Hash256),
|
||||
Invalid(ExecutionBlockHash),
|
||||
/// An EL has not yet verified the execution payload.
|
||||
Unknown(Hash256),
|
||||
Unknown(ExecutionBlockHash),
|
||||
/// The block is either prior to the merge fork, or after the merge fork but before the terminal
|
||||
/// PoW block has been found.
|
||||
///
|
||||
@@ -41,7 +44,7 @@ impl ExecutionStatus {
|
||||
ExecutionStatus::Irrelevant(false)
|
||||
}
|
||||
|
||||
pub fn block_hash(&self) -> Option<Hash256> {
|
||||
pub fn block_hash(&self) -> Option<ExecutionBlockHash> {
|
||||
match self {
|
||||
ExecutionStatus::Valid(hash)
|
||||
| ExecutionStatus::Invalid(hash)
|
||||
@@ -49,6 +52,37 @@ impl ExecutionStatus {
|
||||
ExecutionStatus::Irrelevant(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the block:
|
||||
///
|
||||
/// - Has execution enabled
|
||||
/// - Has a valid payload
|
||||
pub fn is_valid(&self) -> bool {
|
||||
matches!(self, ExecutionStatus::Valid(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if the block:
|
||||
///
|
||||
/// - Has execution enabled
|
||||
/// - Has a payload that has not yet been verified by an EL.
|
||||
pub fn is_not_verified(&self) -> bool {
|
||||
matches!(self, ExecutionStatus::Unknown(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if the block:
|
||||
///
|
||||
/// - Has execution enabled
|
||||
/// - Has an invalid payload.
|
||||
pub fn is_invalid(&self) -> bool {
|
||||
matches!(self, ExecutionStatus::Invalid(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if the block:
|
||||
///
|
||||
/// - Does not have execution enabled (before or after Bellatrix fork)
|
||||
pub fn is_irrelevant(&self) -> bool {
|
||||
matches!(self, ExecutionStatus::Irrelevant(_))
|
||||
}
|
||||
}
|
||||
|
||||
/// A block that is to be applied to the fork choice.
|
||||
@@ -150,6 +184,17 @@ impl ProtoArrayForkChoice {
|
||||
})
|
||||
}
|
||||
|
||||
/// See `ProtoArray::propagate_execution_payload_invalidation` for documentation.
|
||||
pub fn process_execution_payload_invalidation(
|
||||
&mut self,
|
||||
head_block_root: Hash256,
|
||||
latest_valid_ancestor_root: Option<ExecutionBlockHash>,
|
||||
) -> Result<(), String> {
|
||||
self.proto_array
|
||||
.propagate_execution_payload_invalidation(head_block_root, latest_valid_ancestor_root)
|
||||
.map_err(|e| format!("Failed to process invalid payload: {:?}", e))
|
||||
}
|
||||
|
||||
pub fn process_attestation(
|
||||
&mut self,
|
||||
validator_index: usize,
|
||||
@@ -267,25 +312,19 @@ impl ProtoArrayForkChoice {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the `descendant_root` has an ancestor with `ancestor_root`. Always
|
||||
/// returns `false` if either input roots are unknown.
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// Still returns `true` if `ancestor_root` is known and `ancestor_root == descendant_root`.
|
||||
/// Returns the weight of a given block.
|
||||
pub fn get_weight(&self, block_root: &Hash256) -> Option<u64> {
|
||||
let block_index = self.proto_array.indices.get(block_root)?;
|
||||
self.proto_array
|
||||
.nodes
|
||||
.get(*block_index)
|
||||
.map(|node| node.weight)
|
||||
}
|
||||
|
||||
/// See `ProtoArray` documentation.
|
||||
pub fn is_descendant(&self, ancestor_root: Hash256, descendant_root: Hash256) -> bool {
|
||||
self.proto_array
|
||||
.indices
|
||||
.get(&ancestor_root)
|
||||
.and_then(|ancestor_index| self.proto_array.nodes.get(*ancestor_index))
|
||||
.and_then(|ancestor| {
|
||||
self.proto_array
|
||||
.iter_block_roots(&descendant_root)
|
||||
.take_while(|(_root, slot)| *slot >= ancestor.slot)
|
||||
.find(|(_root, slot)| *slot == ancestor.slot)
|
||||
.map(|(root, _slot)| root == ancestor_root)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
.is_descendant(ancestor_root, descendant_root)
|
||||
}
|
||||
|
||||
pub fn latest_message(&self, validator_index: usize) -> Option<(Hash256, Epoch)> {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "safe_arith"
|
||||
version = "0.1.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "eth2_serde_utils"
|
||||
version = "0.1.1"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com", "Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Serialization and deserialization utilities useful for JSON representations of Ethereum 2.0 types."
|
||||
license = "Apache-2.0"
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ where
|
||||
let raw = hex::encode(num.to_be_bytes());
|
||||
let trimmed = raw.trim_start_matches('0');
|
||||
|
||||
let hex = if trimmed.is_empty() { "0" } else { &trimmed };
|
||||
let hex = if trimmed.is_empty() { "0" } else { trimmed };
|
||||
|
||||
serializer.serialize_str(&format!("0x{}", &hex))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "eth2_ssz"
|
||||
version = "0.4.1"
|
||||
authors = ["Paul Hauner <paul@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "SimpleSerialize (SSZ) as used in Ethereum 2.0"
|
||||
license = "Apache-2.0"
|
||||
|
||||
|
||||
@@ -187,12 +187,13 @@ impl<'a> SszDecoderBuilder<'a> {
|
||||
let start = self.items_index;
|
||||
self.items_index += ssz_fixed_len;
|
||||
|
||||
let slice = self.bytes.get(start..self.items_index).ok_or_else(|| {
|
||||
DecodeError::InvalidByteLength {
|
||||
len: self.bytes.len(),
|
||||
expected: self.items_index,
|
||||
}
|
||||
})?;
|
||||
let slice =
|
||||
self.bytes
|
||||
.get(start..self.items_index)
|
||||
.ok_or(DecodeError::InvalidByteLength {
|
||||
len: self.bytes.len(),
|
||||
expected: self.items_index,
|
||||
})?;
|
||||
|
||||
self.items.push(slice);
|
||||
} else {
|
||||
@@ -347,12 +348,12 @@ pub fn split_union_bytes(bytes: &[u8]) -> Result<(UnionSelector, &[u8]), DecodeE
|
||||
/// Reads a `BYTES_PER_LENGTH_OFFSET`-byte length from `bytes`, where `bytes.len() >=
|
||||
/// BYTES_PER_LENGTH_OFFSET`.
|
||||
pub fn read_offset(bytes: &[u8]) -> Result<usize, DecodeError> {
|
||||
decode_offset(bytes.get(0..BYTES_PER_LENGTH_OFFSET).ok_or_else(|| {
|
||||
decode_offset(bytes.get(0..BYTES_PER_LENGTH_OFFSET).ok_or(
|
||||
DecodeError::InvalidLengthPrefix {
|
||||
len: bytes.len(),
|
||||
expected: BYTES_PER_LENGTH_OFFSET,
|
||||
}
|
||||
})?)
|
||||
},
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Decode bytes as a little-endian usize, returning an `Err` if `bytes.len() !=
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "eth2_ssz_derive"
|
||||
version = "0.3.0"
|
||||
authors = ["Paul Hauner <paul@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Procedural derive macros to accompany the eth2_ssz crate."
|
||||
license = "Apache-2.0"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "eth2_ssz_types"
|
||||
version = "0.2.2"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Provides types with unique properties required for SSZ serialization and Merklization."
|
||||
license = "Apache-2.0"
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ pub type BitVector<N> = Bitfield<Fixed<N>>;
|
||||
///
|
||||
/// The internal representation of the bitfield is the same as that required by SSZ. The lowest
|
||||
/// byte (by `Vec` index) stores the lowest bit-indices and the right-most bit stores the lowest
|
||||
/// bit-index. E.g., `vec![0b0000_0001, 0b0000_0010]` has bits `0, 9` set.
|
||||
/// bit-index. E.g., `smallvec![0b0000_0001, 0b0000_0010]` has bits `0, 9` set.
|
||||
#[derive(Clone, Debug, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = ""))]
|
||||
pub struct Bitfield<T> {
|
||||
@@ -138,12 +138,13 @@ impl<N: Unsigned + Clone> Bitfield<Variable<N>> {
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// use ssz_types::{BitList, typenum};
|
||||
/// use smallvec::SmallVec;
|
||||
///
|
||||
/// type BitList8 = BitList<typenum::U8>;
|
||||
///
|
||||
/// let b = BitList8::with_capacity(4).unwrap();
|
||||
///
|
||||
/// assert_eq!(b.into_bytes(), vec![0b0001_0000]);
|
||||
/// assert_eq!(b.into_bytes(), SmallVec::from_buf([0b0001_0000]));
|
||||
/// ```
|
||||
pub fn into_bytes(self) -> SmallVec<[u8; SMALLVEC_LEN]> {
|
||||
let len = self.len();
|
||||
@@ -260,10 +261,11 @@ impl<N: Unsigned + Clone> Bitfield<Fixed<N>> {
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// use ssz_types::{BitVector, typenum};
|
||||
/// use smallvec::SmallVec;
|
||||
///
|
||||
/// type BitVector4 = BitVector<typenum::U4>;
|
||||
///
|
||||
/// assert_eq!(BitVector4::new().into_bytes(), vec![0b0000_0000]);
|
||||
/// assert_eq!(BitVector4::new().into_bytes(), SmallVec::from_buf([0b0000_0000]));
|
||||
/// ```
|
||||
pub fn into_bytes(self) -> SmallVec<[u8; SMALLVEC_LEN]> {
|
||||
self.into_raw_bytes()
|
||||
@@ -656,7 +658,7 @@ impl<N: Unsigned + Clone> tree_hash::TreeHash for Bitfield<Fixed<N>> {
|
||||
impl<N: 'static + Unsigned> arbitrary::Arbitrary<'_> for Bitfield<Fixed<N>> {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
let size = N::to_usize();
|
||||
let mut vec: Vec<u8> = vec![0u8; size];
|
||||
let mut vec = smallvec![0u8; size];
|
||||
u.fill_buffer(&mut vec)?;
|
||||
Ok(Self::from_bytes(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?)
|
||||
}
|
||||
@@ -668,7 +670,7 @@ impl<N: 'static + Unsigned> arbitrary::Arbitrary<'_> for Bitfield<Variable<N>> {
|
||||
let max_size = N::to_usize();
|
||||
let rand = usize::arbitrary(u)?;
|
||||
let size = std::cmp::min(rand, max_size);
|
||||
let mut vec: Vec<u8> = vec![0u8; size];
|
||||
let mut vec = smallvec![0u8; size];
|
||||
u.fill_buffer(&mut vec)?;
|
||||
Ok(Self::from_bytes(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?)
|
||||
}
|
||||
@@ -737,9 +739,9 @@ mod bitvector {
|
||||
|
||||
#[test]
|
||||
fn intersection() {
|
||||
let a = BitVector16::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitVector16::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitVector16::from_raw_bytes(vec![0b1000, 0b0001], 16).unwrap();
|
||||
let a = BitVector16::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitVector16::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitVector16::from_raw_bytes(smallvec![0b1000, 0b0001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.intersection(&b), c);
|
||||
assert_eq!(b.intersection(&a), c);
|
||||
@@ -752,9 +754,9 @@ mod bitvector {
|
||||
|
||||
#[test]
|
||||
fn intersection_diff_length() {
|
||||
let a = BitVector16::from_bytes(vec![0b0010_1110, 0b0010_1011]).unwrap();
|
||||
let b = BitVector16::from_bytes(vec![0b0010_1101, 0b0000_0001]).unwrap();
|
||||
let c = BitVector16::from_bytes(vec![0b0010_1100, 0b0000_0001]).unwrap();
|
||||
let a = BitVector16::from_bytes(smallvec![0b0010_1110, 0b0010_1011]).unwrap();
|
||||
let b = BitVector16::from_bytes(smallvec![0b0010_1101, 0b0000_0001]).unwrap();
|
||||
let c = BitVector16::from_bytes(smallvec![0b0010_1100, 0b0000_0001]).unwrap();
|
||||
|
||||
assert_eq!(a.len(), 16);
|
||||
assert_eq!(b.len(), 16);
|
||||
@@ -765,9 +767,9 @@ mod bitvector {
|
||||
|
||||
#[test]
|
||||
fn union() {
|
||||
let a = BitVector16::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitVector16::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitVector16::from_raw_bytes(vec![0b1111, 0b1001], 16).unwrap();
|
||||
let a = BitVector16::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitVector16::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitVector16::from_raw_bytes(smallvec![0b1111, 0b1001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.union(&b), c);
|
||||
assert_eq!(b.union(&a), c);
|
||||
@@ -778,9 +780,9 @@ mod bitvector {
|
||||
|
||||
#[test]
|
||||
fn union_diff_length() {
|
||||
let a = BitVector16::from_bytes(vec![0b0010_1011, 0b0010_1110]).unwrap();
|
||||
let b = BitVector16::from_bytes(vec![0b0000_0001, 0b0010_1101]).unwrap();
|
||||
let c = BitVector16::from_bytes(vec![0b0010_1011, 0b0010_1111]).unwrap();
|
||||
let a = BitVector16::from_bytes(smallvec![0b0010_1011, 0b0010_1110]).unwrap();
|
||||
let b = BitVector16::from_bytes(smallvec![0b0000_0001, 0b0010_1101]).unwrap();
|
||||
let c = BitVector16::from_bytes(smallvec![0b0010_1011, 0b0010_1111]).unwrap();
|
||||
|
||||
assert_eq!(a.len(), c.len());
|
||||
assert_eq!(a.union(&b), c);
|
||||
@@ -846,6 +848,12 @@ mod bitvector {
|
||||
|
||||
assert!(BitVector4::from_ssz_bytes(&bad).is_err());
|
||||
}
|
||||
|
||||
// Ensure that stack size of a BitVector is manageable.
|
||||
#[test]
|
||||
fn size_of() {
|
||||
assert_eq!(std::mem::size_of::<BitVector64>(), SMALLVEC_LEN + 24);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -999,50 +1007,50 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn from_raw_bytes() {
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0000], 0).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0001], 1).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0011], 2).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0111], 3).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_1111], 4).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0001_1111], 5).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0011_1111], 6).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0111_1111], 7).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111], 8).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0000], 0).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0001], 1).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0011], 2).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0111], 3).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_1111], 4).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0001_1111], 5).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0011_1111], 6).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0111_1111], 7).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111], 8).is_ok());
|
||||
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0001], 9).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0011], 10).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0111], 11).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_1111], 12).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0001_1111], 13).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0011_1111], 14).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0111_1111], 15).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b1111_1111], 16).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0001], 9).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0011], 10).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0111], 11).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_1111], 12).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0001_1111], 13).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0011_1111], 14).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0111_1111], 15).is_ok());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b1111_1111], 16).is_ok());
|
||||
|
||||
for i in 0..8 {
|
||||
assert!(BitList1024::from_raw_bytes(vec![], i).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111], i).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0000, 0b1111_1110], i).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![], i).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111], i).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0000, 0b1111_1110], i).is_err());
|
||||
}
|
||||
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0001], 0).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0001], 0).is_err());
|
||||
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0001], 0).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0011], 1).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_0111], 2).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0000_1111], 3).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0001_1111], 4).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0011_1111], 5).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b0111_1111], 6).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111], 7).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0001], 0).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0011], 1).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_0111], 2).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0000_1111], 3).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0001_1111], 4).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0011_1111], 5).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b0111_1111], 6).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111], 7).is_err());
|
||||
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0001], 8).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0011], 9).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_0111], 10).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0000_1111], 11).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0001_1111], 12).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0011_1111], 13).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b0111_1111], 14).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(vec![0b1111_1111, 0b1111_1111], 15).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0001], 8).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0011], 9).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_0111], 10).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0000_1111], 11).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0001_1111], 12).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0011_1111], 13).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b0111_1111], 14).is_err());
|
||||
assert!(BitList1024::from_raw_bytes(smallvec![0b1111_1111, 0b1111_1111], 15).is_err());
|
||||
}
|
||||
|
||||
fn test_set_unset(num_bits: usize) {
|
||||
@@ -1090,51 +1098,64 @@ mod bitlist {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type-specialised `smallvec` macro for testing.
|
||||
macro_rules! bytevec {
|
||||
($($x : expr),* $(,)*) => {
|
||||
{
|
||||
let __smallvec: SmallVec<[u8; SMALLVEC_LEN]> = smallvec!($($x),*);
|
||||
__smallvec
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_raw_bytes() {
|
||||
let mut bitfield = BitList1024::with_capacity(9).unwrap();
|
||||
bitfield.set(0, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0000_0001, 0b0000_0000]
|
||||
bytevec![0b0000_0001, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(1, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0000_0011, 0b0000_0000]
|
||||
bytevec![0b0000_0011, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(2, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0000_0111, 0b0000_0000]
|
||||
bytevec![0b0000_0111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(3, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0000_1111, 0b0000_0000]
|
||||
bytevec![0b0000_1111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(4, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0001_1111, 0b0000_0000]
|
||||
bytevec![0b0001_1111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(5, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0011_1111, 0b0000_0000]
|
||||
bytevec![0b0011_1111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(6, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b0111_1111, 0b0000_0000]
|
||||
bytevec![0b0111_1111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(7, true).unwrap();
|
||||
assert_eq!(
|
||||
bitfield.clone().into_raw_bytes(),
|
||||
vec![0b1111_1111, 0b0000_0000]
|
||||
bytevec![0b1111_1111, 0b0000_0000]
|
||||
);
|
||||
bitfield.set(8, true).unwrap();
|
||||
assert_eq!(bitfield.into_raw_bytes(), vec![0b1111_1111, 0b0000_0001]);
|
||||
assert_eq!(
|
||||
bitfield.into_raw_bytes(),
|
||||
bytevec![0b1111_1111, 0b0000_0001]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1145,28 +1166,28 @@ mod bitlist {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BitList1024::from_raw_bytes(vec![0b0000_0001, 0b0000_0000], 16)
|
||||
BitList1024::from_raw_bytes(smallvec![0b0000_0001, 0b0000_0000], 16)
|
||||
.unwrap()
|
||||
.highest_set_bit(),
|
||||
Some(0)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BitList1024::from_raw_bytes(vec![0b0000_0010, 0b0000_0000], 16)
|
||||
BitList1024::from_raw_bytes(smallvec![0b0000_0010, 0b0000_0000], 16)
|
||||
.unwrap()
|
||||
.highest_set_bit(),
|
||||
Some(1)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BitList1024::from_raw_bytes(vec![0b0000_1000], 8)
|
||||
BitList1024::from_raw_bytes(smallvec![0b0000_1000], 8)
|
||||
.unwrap()
|
||||
.highest_set_bit(),
|
||||
Some(3)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BitList1024::from_raw_bytes(vec![0b0000_0000, 0b1000_0000], 16)
|
||||
BitList1024::from_raw_bytes(smallvec![0b0000_0000, 0b1000_0000], 16)
|
||||
.unwrap()
|
||||
.highest_set_bit(),
|
||||
Some(15)
|
||||
@@ -1175,9 +1196,9 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn intersection() {
|
||||
let a = BitList1024::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitList1024::from_raw_bytes(vec![0b1000, 0b0001], 16).unwrap();
|
||||
let a = BitList1024::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitList1024::from_raw_bytes(smallvec![0b1000, 0b0001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.intersection(&b), c);
|
||||
assert_eq!(b.intersection(&a), c);
|
||||
@@ -1190,10 +1211,10 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn intersection_diff_length() {
|
||||
let a = BitList1024::from_bytes(vec![0b0010_1110, 0b0010_1011]).unwrap();
|
||||
let b = BitList1024::from_bytes(vec![0b0010_1101, 0b0000_0001]).unwrap();
|
||||
let c = BitList1024::from_bytes(vec![0b0010_1100, 0b0000_0001]).unwrap();
|
||||
let d = BitList1024::from_bytes(vec![0b0010_1110, 0b1111_1111, 0b1111_1111]).unwrap();
|
||||
let a = BitList1024::from_bytes(smallvec![0b0010_1110, 0b0010_1011]).unwrap();
|
||||
let b = BitList1024::from_bytes(smallvec![0b0010_1101, 0b0000_0001]).unwrap();
|
||||
let c = BitList1024::from_bytes(smallvec![0b0010_1100, 0b0000_0001]).unwrap();
|
||||
let d = BitList1024::from_bytes(smallvec![0b0010_1110, 0b1111_1111, 0b1111_1111]).unwrap();
|
||||
|
||||
assert_eq!(a.len(), 13);
|
||||
assert_eq!(b.len(), 8);
|
||||
@@ -1207,9 +1228,9 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn union() {
|
||||
let a = BitList1024::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitList1024::from_raw_bytes(vec![0b1111, 0b1001], 16).unwrap();
|
||||
let a = BitList1024::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let c = BitList1024::from_raw_bytes(smallvec![0b1111, 0b1001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.union(&b), c);
|
||||
assert_eq!(b.union(&a), c);
|
||||
@@ -1220,10 +1241,10 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn union_diff_length() {
|
||||
let a = BitList1024::from_bytes(vec![0b0010_1011, 0b0010_1110]).unwrap();
|
||||
let b = BitList1024::from_bytes(vec![0b0000_0001, 0b0010_1101]).unwrap();
|
||||
let c = BitList1024::from_bytes(vec![0b0010_1011, 0b0010_1111]).unwrap();
|
||||
let d = BitList1024::from_bytes(vec![0b0010_1011, 0b1011_1110, 0b1000_1101]).unwrap();
|
||||
let a = BitList1024::from_bytes(smallvec![0b0010_1011, 0b0010_1110]).unwrap();
|
||||
let b = BitList1024::from_bytes(smallvec![0b0000_0001, 0b0010_1101]).unwrap();
|
||||
let c = BitList1024::from_bytes(smallvec![0b0010_1011, 0b0010_1111]).unwrap();
|
||||
let d = BitList1024::from_bytes(smallvec![0b0010_1011, 0b1011_1110, 0b1000_1101]).unwrap();
|
||||
|
||||
assert_eq!(a.len(), c.len());
|
||||
assert_eq!(a.union(&b), c);
|
||||
@@ -1234,10 +1255,10 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn difference() {
|
||||
let a = BitList1024::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let a_b = BitList1024::from_raw_bytes(vec![0b0100, 0b0000], 16).unwrap();
|
||||
let b_a = BitList1024::from_raw_bytes(vec![0b0011, 0b1000], 16).unwrap();
|
||||
let a = BitList1024::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let a_b = BitList1024::from_raw_bytes(smallvec![0b0100, 0b0000], 16).unwrap();
|
||||
let b_a = BitList1024::from_raw_bytes(smallvec![0b0011, 0b1000], 16).unwrap();
|
||||
|
||||
assert_eq!(a.difference(&b), a_b);
|
||||
assert_eq!(b.difference(&a), b_a);
|
||||
@@ -1246,10 +1267,10 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn difference_diff_length() {
|
||||
let a = BitList1024::from_raw_bytes(vec![0b0110, 0b1100, 0b0011], 24).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let a_b = BitList1024::from_raw_bytes(vec![0b0100, 0b0100, 0b0011], 24).unwrap();
|
||||
let b_a = BitList1024::from_raw_bytes(vec![0b1001, 0b0001], 16).unwrap();
|
||||
let a = BitList1024::from_raw_bytes(smallvec![0b0110, 0b1100, 0b0011], 24).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
let a_b = BitList1024::from_raw_bytes(smallvec![0b0100, 0b0100, 0b0011], 24).unwrap();
|
||||
let b_a = BitList1024::from_raw_bytes(smallvec![0b1001, 0b0001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.difference(&b), a_b);
|
||||
assert_eq!(b.difference(&a), b_a);
|
||||
@@ -1257,8 +1278,8 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn shift_up() {
|
||||
let mut a = BitList1024::from_raw_bytes(vec![0b1100_1111, 0b1101_0110], 16).unwrap();
|
||||
let mut b = BitList1024::from_raw_bytes(vec![0b1001_1110, 0b1010_1101], 16).unwrap();
|
||||
let mut a = BitList1024::from_raw_bytes(smallvec![0b1100_1111, 0b1101_0110], 16).unwrap();
|
||||
let mut b = BitList1024::from_raw_bytes(smallvec![0b1001_1110, 0b1010_1101], 16).unwrap();
|
||||
|
||||
a.shift_up(1).unwrap();
|
||||
assert_eq!(a, b);
|
||||
@@ -1272,8 +1293,8 @@ mod bitlist {
|
||||
|
||||
#[test]
|
||||
fn num_set_bits() {
|
||||
let a = BitList1024::from_raw_bytes(vec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(vec![0b1011, 0b1001], 16).unwrap();
|
||||
let a = BitList1024::from_raw_bytes(smallvec![0b1100, 0b0001], 16).unwrap();
|
||||
let b = BitList1024::from_raw_bytes(smallvec![0b1011, 0b1001], 16).unwrap();
|
||||
|
||||
assert_eq!(a.num_set_bits(), 3);
|
||||
assert_eq!(b.num_set_bits(), 5);
|
||||
@@ -1302,4 +1323,10 @@ mod bitlist {
|
||||
assert_eq!(bitfield.ssz_bytes_len(), bytes.len(), "i = {}", i);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the stack size of a BitList is manageable.
|
||||
#[test]
|
||||
fn size_of() {
|
||||
assert_eq!(std::mem::size_of::<BitList1024>(), SMALLVEC_LEN + 24);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "state_processing"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.9.0"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
not(test),
|
||||
deny(
|
||||
clippy::integer_arithmetic,
|
||||
clippy::disallowed_method,
|
||||
clippy::disallowed_methods,
|
||||
clippy::indexing_slicing,
|
||||
clippy::unwrap_used,
|
||||
clippy::expect_used,
|
||||
|
||||
@@ -370,7 +370,7 @@ pub fn process_execution_payload<T: EthSpec>(
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipt_root: payload.receipt_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
random: payload.random,
|
||||
block_number: payload.block_number,
|
||||
|
||||
@@ -59,8 +59,8 @@ pub enum BlockProcessingError {
|
||||
InconsistentBlockFork(InconsistentFork),
|
||||
InconsistentStateFork(InconsistentFork),
|
||||
ExecutionHashChainIncontiguous {
|
||||
expected: Hash256,
|
||||
found: Hash256,
|
||||
expected: ExecutionBlockHash,
|
||||
found: ExecutionBlockHash,
|
||||
},
|
||||
ExecutionRandaoMismatch {
|
||||
expected: Hash256,
|
||||
|
||||
@@ -177,7 +177,7 @@ where
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
block.body().randao_reveal(),
|
||||
get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
message,
|
||||
))
|
||||
}
|
||||
@@ -199,15 +199,13 @@ where
|
||||
block_header_signature_set(
|
||||
state,
|
||||
&proposer_slashing.signed_header_1,
|
||||
get_pubkey(proposer_index)
|
||||
.ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
spec,
|
||||
),
|
||||
block_header_signature_set(
|
||||
state,
|
||||
&proposer_slashing.signed_header_2,
|
||||
get_pubkey(proposer_index)
|
||||
.ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
spec,
|
||||
),
|
||||
))
|
||||
@@ -363,7 +361,7 @@ where
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
&signed_exit.signature,
|
||||
get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
message,
|
||||
))
|
||||
}
|
||||
@@ -521,7 +519,7 @@ where
|
||||
{
|
||||
let mut pubkeys = Vec::with_capacity(T::SyncSubcommitteeSize::to_usize());
|
||||
for pubkey in pubkey_bytes {
|
||||
pubkeys.push(get_pubkey(pubkey).ok_or_else(|| Error::ValidatorPubkeyUnknown(*pubkey))?);
|
||||
pubkeys.push(get_pubkey(pubkey).ok_or(Error::ValidatorPubkeyUnknown(*pubkey))?);
|
||||
}
|
||||
|
||||
let domain = spec.get_domain(epoch, Domain::SyncCommittee, fork, genesis_validators_root);
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::per_epoch_processing::{
|
||||
Delta, Error,
|
||||
};
|
||||
use safe_arith::SafeArith;
|
||||
use std::array::IntoIter as ArrayIter;
|
||||
use types::{BeaconState, ChainSpec, EthSpec};
|
||||
|
||||
/// Combination of several deltas for different components of an attestation reward.
|
||||
@@ -30,13 +29,13 @@ impl AttestationDelta {
|
||||
inactivity_penalty_delta,
|
||||
} = self;
|
||||
let mut result = Delta::default();
|
||||
for delta in ArrayIter::new([
|
||||
for delta in [
|
||||
source_delta,
|
||||
target_delta,
|
||||
head_delta,
|
||||
inclusion_delay_delta,
|
||||
inactivity_penalty_delta,
|
||||
]) {
|
||||
] {
|
||||
result.combine(delta)?;
|
||||
}
|
||||
Ok(result)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "swap_or_not_shuffle"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "tree_hash"
|
||||
version = "0.4.1"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
description = "Efficient Merkle-hashing as used in Ethereum 2.0"
|
||||
|
||||
|
||||
@@ -376,8 +376,8 @@ mod test {
|
||||
fn compare_with_reference(leaves: &[Hash256], depth: usize) {
|
||||
let reference_bytes = leaves
|
||||
.iter()
|
||||
.map(|hash| hash.as_bytes().to_vec())
|
||||
.flatten()
|
||||
.flat_map(|hash| hash.as_bytes())
|
||||
.copied()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let reference_root = merkleize_padded(&reference_bytes, 1 << (depth - 1));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "tree_hash_derive"
|
||||
version = "0.4.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Procedural derive macros to accompany the tree_hash crate."
|
||||
license = "Apache-2.0"
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ fn cached_tree_hash_attr_metas(attrs: &[Attribute]) -> Vec<Meta> {
|
||||
fn should_skip_hashing(field: &syn::Field) -> bool {
|
||||
field.attrs.iter().any(|attr| {
|
||||
attr.path.is_ident("tree_hash")
|
||||
&& attr.tokens.to_string().replace(" ", "") == "(skip_hashing)"
|
||||
&& attr.tokens.to_string().replace(' ', "") == "(skip_hashing)"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "types"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
@@ -45,9 +45,9 @@ parking_lot = "0.11.1"
|
||||
itertools = "0.10.0"
|
||||
superstruct = "0.4.0"
|
||||
serde_json = "1.0.74"
|
||||
smallvec = "1.8.0"
|
||||
milhouse = { path = "../../../milhouse", optional = true }
|
||||
rpds = "0.11.0"
|
||||
smallvec = "1.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.3"
|
||||
|
||||
@@ -110,9 +110,34 @@ impl<T: EthSpec> SlotData for Attestation<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
use super::*;
|
||||
// Check the in-memory size of an `Attestation`, which is useful for reasoning about memory
|
||||
// and preventing regressions.
|
||||
//
|
||||
// This test will only pass with `blst`, if we run these tests with Milagro or another
|
||||
// BLS library in future we will have to make it generic.
|
||||
#[test]
|
||||
fn size_of() {
|
||||
use std::mem::size_of;
|
||||
|
||||
let aggregation_bits =
|
||||
size_of::<BitList<<MainnetEthSpec as EthSpec>::MaxValidatorsPerCommittee>>();
|
||||
let attestation_data = size_of::<AttestationData>();
|
||||
let signature = size_of::<AggregateSignature>();
|
||||
|
||||
assert_eq!(aggregation_bits, 56);
|
||||
assert_eq!(attestation_data, 128);
|
||||
assert_eq!(signature, 288 + 16);
|
||||
|
||||
let attestation_expected = aggregation_bits + attestation_data + signature;
|
||||
assert_eq!(attestation_expected, 488);
|
||||
assert_eq!(
|
||||
size_of::<Attestation<MainnetEthSpec>>(),
|
||||
attestation_expected
|
||||
);
|
||||
}
|
||||
|
||||
ssz_and_tree_hash_tests!(Attestation<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
#![allow(clippy::disallowed_method)]
|
||||
#![allow(clippy::disallowed_methods)]
|
||||
#![allow(clippy::indexing_slicing)]
|
||||
|
||||
use super::Error;
|
||||
|
||||
@@ -28,6 +28,11 @@ pub enum Domain {
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct ChainSpec {
|
||||
/*
|
||||
* Config name
|
||||
*/
|
||||
pub config_name: Option<String>,
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
@@ -139,7 +144,7 @@ pub struct ChainSpec {
|
||||
/// The Merge fork epoch is optional, with `None` representing "Merge never happens".
|
||||
pub bellatrix_fork_epoch: Option<Epoch>,
|
||||
pub terminal_total_difficulty: Uint256,
|
||||
pub terminal_block_hash: Hash256,
|
||||
pub terminal_block_hash: ExecutionBlockHash,
|
||||
pub terminal_block_hash_activation_epoch: Epoch,
|
||||
|
||||
/*
|
||||
@@ -412,6 +417,10 @@ impl ChainSpec {
|
||||
/// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
|
||||
pub fn mainnet() -> Self {
|
||||
Self {
|
||||
/*
|
||||
* Config name
|
||||
*/
|
||||
config_name: Some("mainnet".to_string()),
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
@@ -547,7 +556,7 @@ impl ChainSpec {
|
||||
// `Uint256::MAX` which is `2*256- 1`.
|
||||
.checked_add(Uint256::one())
|
||||
.expect("addition does not overflow"),
|
||||
terminal_block_hash: Hash256::zero(),
|
||||
terminal_block_hash: ExecutionBlockHash::zero(),
|
||||
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
|
||||
|
||||
/*
|
||||
@@ -570,6 +579,7 @@ impl ChainSpec {
|
||||
let boot_nodes = vec![];
|
||||
|
||||
Self {
|
||||
config_name: None,
|
||||
max_committees_per_slot: 4,
|
||||
target_committee_size: 4,
|
||||
churn_limit_quotient: 32,
|
||||
@@ -607,6 +617,7 @@ impl ChainSpec {
|
||||
/// Returns a `ChainSpec` compatible with the Gnosis Beacon Chain specification.
|
||||
pub fn gnosis() -> Self {
|
||||
Self {
|
||||
config_name: Some("gnosis".to_string()),
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
@@ -742,7 +753,7 @@ impl ChainSpec {
|
||||
// `Uint256::MAX` which is `2*256- 1`.
|
||||
.checked_add(Uint256::one())
|
||||
.expect("addition does not overflow"),
|
||||
terminal_block_hash: Hash256::zero(),
|
||||
terminal_block_hash: ExecutionBlockHash::zero(),
|
||||
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
|
||||
|
||||
/*
|
||||
@@ -770,6 +781,10 @@ impl Default for ChainSpec {
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub config_name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub preset_base: String,
|
||||
|
||||
@@ -779,7 +794,7 @@ pub struct Config {
|
||||
pub terminal_total_difficulty: Uint256,
|
||||
// TODO(merge): remove this default
|
||||
#[serde(default = "default_terminal_block_hash")]
|
||||
pub terminal_block_hash: Hash256,
|
||||
pub terminal_block_hash: ExecutionBlockHash,
|
||||
// TODO(merge): remove this default
|
||||
#[serde(default = "default_terminal_block_hash_activation_epoch")]
|
||||
pub terminal_block_hash_activation_epoch: Epoch,
|
||||
@@ -862,8 +877,8 @@ const fn default_terminal_total_difficulty() -> Uint256 {
|
||||
])
|
||||
}
|
||||
|
||||
fn default_terminal_block_hash() -> Hash256 {
|
||||
Hash256::zero()
|
||||
fn default_terminal_block_hash() -> ExecutionBlockHash {
|
||||
ExecutionBlockHash::zero()
|
||||
}
|
||||
|
||||
fn default_terminal_block_hash_activation_epoch() -> Epoch {
|
||||
@@ -921,6 +936,7 @@ impl Config {
|
||||
|
||||
pub fn from_chain_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
|
||||
Self {
|
||||
config_name: spec.config_name.clone(),
|
||||
preset_base: T::spec_name().to_string(),
|
||||
|
||||
terminal_total_difficulty: spec.terminal_total_difficulty,
|
||||
@@ -971,6 +987,7 @@ impl Config {
|
||||
pub fn apply_to_chain_spec<T: EthSpec>(&self, chain_spec: &ChainSpec) -> Option<ChainSpec> {
|
||||
// Pattern match here to avoid missing any fields.
|
||||
let &Config {
|
||||
ref config_name,
|
||||
ref preset_base,
|
||||
terminal_total_difficulty,
|
||||
terminal_block_hash,
|
||||
@@ -1004,6 +1021,7 @@ impl Config {
|
||||
}
|
||||
|
||||
Some(ChainSpec {
|
||||
config_name: config_name.clone(),
|
||||
min_genesis_active_validator_count,
|
||||
min_genesis_time,
|
||||
genesis_fork_version,
|
||||
|
||||
@@ -46,7 +46,6 @@ impl ConfigAndPreset {
|
||||
let u32_hex = |v: u32| hex_string(&v.to_le_bytes());
|
||||
let u8_hex = |v: u8| hex_string(&v.to_le_bytes());
|
||||
let fields = vec![
|
||||
("config_name", self.config.preset_base.clone()),
|
||||
(
|
||||
"bls_withdrawal_prefix",
|
||||
u8_hex(spec.bls_withdrawal_prefix_byte),
|
||||
|
||||
101
consensus/types/src/execution_block_hash.rs
Normal file
101
consensus/types/src/execution_block_hash.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::Hash256;
|
||||
use rand::RngCore;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::fmt;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[serde(transparent)]
|
||||
pub struct ExecutionBlockHash(Hash256);
|
||||
|
||||
impl ExecutionBlockHash {
|
||||
pub fn zero() -> Self {
|
||||
Self(Hash256::zero())
|
||||
}
|
||||
|
||||
pub fn repeat_byte(b: u8) -> Self {
|
||||
Self(Hash256::repeat_byte(b))
|
||||
}
|
||||
|
||||
pub fn from_root(root: Hash256) -> Self {
|
||||
Self(root)
|
||||
}
|
||||
|
||||
pub fn into_root(self) -> Hash256 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for ExecutionBlockHash {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<Hash256 as Encode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_fixed_len() -> usize {
|
||||
<Hash256 as Encode>::ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_bytes_len(&self) -> usize {
|
||||
self.0.ssz_bytes_len()
|
||||
}
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
self.0.ssz_append(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for ExecutionBlockHash {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<Hash256 as Decode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_fixed_len() -> usize {
|
||||
<Hash256 as Decode>::ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
Hash256::from_ssz_bytes(bytes).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl tree_hash::TreeHash for ExecutionBlockHash {
|
||||
fn tree_hash_type() -> tree_hash::TreeHashType {
|
||||
Hash256::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding {
|
||||
self.0.tree_hash_packed_encoding()
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
Hash256::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> tree_hash::Hash256 {
|
||||
self.0.tree_hash_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestRandom for ExecutionBlockHash {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
Self(Hash256::random_for_test(rng))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ExecutionBlockHash {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Hash256::from_str(s)
|
||||
.map(Self)
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExecutionBlockHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,10 @@ pub type Transaction<T> = VariableList<u8, T>;
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub parent_hash: Hash256,
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
pub fee_recipient: Address,
|
||||
pub state_root: Hash256,
|
||||
pub receipt_root: Hash256,
|
||||
pub receipts_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
pub random: Hash256,
|
||||
@@ -37,7 +37,7 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
pub base_fee_per_gas: Uint256,
|
||||
pub block_hash: Hash256,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions:
|
||||
VariableList<Transaction<T::MaxBytesPerTransaction>, T::MaxTransactionsPerPayload>,
|
||||
|
||||
@@ -12,10 +12,10 @@ use ssz_types::{FixedVector, VariableList};
|
||||
Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
pub parent_hash: Hash256,
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
pub fee_recipient: Address,
|
||||
pub state_root: Hash256,
|
||||
pub receipt_root: Hash256,
|
||||
pub receipts_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
pub random: Hash256,
|
||||
@@ -31,7 +31,7 @@ pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
pub base_fee_per_gas: Uint256,
|
||||
pub block_hash: Hash256,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
pub transactions_root: Hash256,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
not(test),
|
||||
deny(
|
||||
clippy::integer_arithmetic,
|
||||
clippy::disallowed_method,
|
||||
clippy::disallowed_methods,
|
||||
clippy::indexing_slicing
|
||||
)
|
||||
)]
|
||||
@@ -37,6 +37,7 @@ pub mod deposit_message;
|
||||
pub mod enr_fork_id;
|
||||
pub mod eth1_data;
|
||||
pub mod eth_spec;
|
||||
pub mod execution_block_hash;
|
||||
pub mod execution_payload;
|
||||
pub mod execution_payload_header;
|
||||
pub mod fork;
|
||||
@@ -113,6 +114,7 @@ pub use crate::deposit_message::DepositMessage;
|
||||
pub use crate::enr_fork_id::EnrForkId;
|
||||
pub use crate::eth1_data::Eth1Data;
|
||||
pub use crate::eth_spec::EthSpecId;
|
||||
pub use crate::execution_block_hash::ExecutionBlockHash;
|
||||
pub use crate::execution_payload::{ExecutionPayload, Transaction};
|
||||
pub use crate::execution_payload_header::ExecutionPayloadHeader;
|
||||
pub use crate::fork::Fork;
|
||||
|
||||
Reference in New Issue
Block a user