diff --git a/.gitignore b/.gitignore index 346ef9afa..6b8d4ab21 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ Cargo.lock *.pk *.sk *.raw_keypairs +flamegraph.svg +perf.data* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..b21fd7ba9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,36 @@ +#Adapted from https://users.rust-lang.org/t/my-gitlab-config-docs-tests/16396 + +image: 'sigp/lighthouse:latest' + +stages: + - test + - document + +variables: + CARGO_HOME: /cache/cargocache + +check-fmt: + stage: test + script: + - cargo build --manifest-path protos/Cargo.toml + - cargo fmt --all -- --check + +test-dev: + stage: test + script: + - cargo test --verbose --all + +test-release: + stage: test + script: + - cargo test --verbose --all --release + +documentation: + stage: document + script: + - cargo doc --no-deps + - aws s3 sync target/doc/ s3://lighthouse-docs.sigmaprime.io/ --exclude '.lock' --delete + # Configure the below when we want to have a default page (and update S3 bucket index). + # - echo '' > public/index.html + only: + - master diff --git a/.travis.yml b/.travis.yml index e725aa0ba..3662e17cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ language: rust +cache: + directories: + - /home/travis/.cargo before_install: - curl -OL https://github.com/google/protobuf/releases/download/v3.4.0/protoc-3.4.0-linux-x86_64.zip - unzip protoc-3.4.0-linux-x86_64.zip -d protoc3 @@ -7,15 +10,8 @@ before_install: - sudo chown $USER /usr/local/bin/protoc - sudo chown -R $USER /usr/local/include/google script: - - cargo build --verbose --all - - cargo build --verbose --release --all - - cargo test --verbose --all - - cargo test --verbose --release --all - - cargo fmt --all -- --check - # No clippy until later... - #- cargo clippy + - cargo build --verbose --all --release rust: - - stable - beta - nightly matrix: @@ -24,4 +20,3 @@ matrix: fast_finish: true install: - rustup component add rustfmt - - rustup component add clippy diff --git a/Cargo.toml b/Cargo.toml index 5c9593f5a..893189941 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,13 @@ [workspace] members = [ - "eth2/attester", - "eth2/block_proposer", "eth2/fork_choice", "eth2/operation_pool", "eth2/state_processing", - "eth2/state_processing/yaml_utils", "eth2/types", "eth2/utils/bls", "eth2/utils/boolean-bitfield", + "eth2/utils/cached_tree_hash", + "eth2/utils/fixed_len_vec", "eth2/utils/hashing", "eth2/utils/honey-badger-split", "eth2/utils/merkle_proof", @@ -18,6 +17,8 @@ members = [ "eth2/utils/ssz", "eth2/utils/ssz_derive", "eth2/utils/swap_or_not_shuffle", + "eth2/utils/tree_hash", + "eth2/utils/tree_hash_derive", "eth2/utils/fisher_yates_shuffle", "eth2/utils/test_random_derive", "beacon_node", @@ -28,7 +29,6 @@ members = [ "beacon_node/rpc", "beacon_node/version", "beacon_node/beacon_chain", - "beacon_node/beacon_chain/test_harness", "protos", "validator_client", "account_manager", diff --git a/Dockerfile b/Dockerfile index 6691efa97..57f677b78 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM rust:latest -RUN apt-get update && apt-get install -y clang libclang-dev cmake build-essential git unzip autoconf libtool +RUN apt-get update && apt-get install -y clang libclang-dev cmake build-essential git unzip autoconf libtool awscli RUN git clone https://github.com/google/protobuf.git && \ cd protobuf && \ @@ -14,8 +14,8 @@ RUN git clone https://github.com/google/protobuf.git && \ rm -r protobuf -RUN mkdir /cargocache && chmod -R ugo+rwX /cargocache +RUN mkdir -p /cache/cargocache && chmod -R ugo+rwX /cache/cargocache -ENV CARGO_HOME /cargocache +ENV CARGO_HOME /cache/cargocache RUN rustup component add rustfmt clippy diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index d12189941..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,29 +0,0 @@ -pipeline { - agent { - dockerfile { - filename 'Dockerfile' - args '-v cargo-cache:/cargocache:rw -e "CARGO_HOME=/cargocache"' - } - } - stages { - stage('Build') { - steps { - sh 'cargo build --verbose --all' - sh 'cargo build --verbose --all --release' - } - } - stage('Check') { - steps { - sh 'cargo fmt --all -- --check' - // No clippy until later... - //sh 'cargo clippy' - } - } - stage('Test') { - steps { - sh 'cargo test --verbose --all' - sh 'cargo test --verbose --all --release' - } - } - } -} diff --git a/README.md b/README.md index 7727154e7..879f9b8fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ # Lighthouse: an Ethereum Serenity client -[![Build Status](https://travis-ci.org/sigp/lighthouse.svg?branch=master)](https://travis-ci.org/sigp/lighthouse) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sigp/lighthouse?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Build Status]][Build Link] [![Doc Status]][Doc Link] [![Gitter Badge]][Gitter Link] + +[Build Status]: https://gitlab.sigmaprime.io/sigp/lighthouse/badges/master/build.svg +[Build Link]: https://gitlab.sigmaprime.io/sigp/lighthouse/pipelines +[Gitter Badge]: https://badges.gitter.im/Join%20Chat.svg +[Gitter Link]: https://gitter.im/sigp/lighthouse +[Doc Status]: https://img.shields.io/badge/docs-master-blue.svg +[Doc Link]: http://lighthouse-docs.sigmaprime.io/ A work-in-progress, open-source implementation of the Serenity Beacon Chain, maintained by Sigma Prime. @@ -24,6 +31,7 @@ present-Ethereum functionality. - [About Lighthouse](docs/lighthouse.md): Goals, Ideology and Ethos surrounding this implementation. - [What is Ethereum Serenity](docs/serenity.md): an introduction to Ethereum Serenity. +- [Lighthouse Technical Documentation](http://lighthouse-docs.sigmaprime.io/): The Rust generated documentation, updated regularly. If you'd like some background on Sigma Prime, please see the [Lighthouse Update \#00](https://lighthouse.sigmaprime.io/update-00.html) blog post or the diff --git a/account_manager/Cargo.toml b/account_manager/Cargo.toml index c26d4b70a..7b561869a 100644 --- a/account_manager/Cargo.toml +++ b/account_manager/Cargo.toml @@ -11,3 +11,4 @@ slog = "^2.2.3" slog-term = "^2.4.0" slog-async = "^2.3.0" validator_client = { path = "../validator_client" } +types = { path = "../eth2/types" } diff --git a/account_manager/README.md b/account_manager/README.md index bf8891f40..6762b937f 100644 --- a/account_manager/README.md +++ b/account_manager/README.md @@ -1,6 +1,6 @@ -# Lighthouse Accounts Manager +# Lighthouse Account Manager -The accounts manager (AM) is a stand-alone binary which allows +The account manager (AM) is a stand-alone binary which allows users to generate and manage the cryptographic keys necessary to interact with Ethereum Serenity. @@ -21,4 +21,14 @@ staking on Ethereum 1.x (TPD) The AM is not a service, and does not run continuously, nor does it interact with any running services. It is intended to be executed separately from other Lighthouse binaries -and produce files which can be consumed by them. \ No newline at end of file +and produce files which can be consumed by them.& + +## Usage + +Simply run `./account_manager generate` to generate a new random private key, +which will be automatically saved to the correct directory. + +If you prefer to use our "deterministic" keys for testing purposes, simply +run `./accounts_manager generate_deterministic -i `, where `index` is +the validator index for the key. This will reliably produce the same key each time +and save it to the directory. \ No newline at end of file diff --git a/account_manager/src/main.rs b/account_manager/src/main.rs index 42c78aaea..c30b5b103 100644 --- a/account_manager/src/main.rs +++ b/account_manager/src/main.rs @@ -2,6 +2,7 @@ use bls::Keypair; use clap::{App, Arg, SubCommand}; use slog::{debug, info, o, Drain}; use std::path::PathBuf; +use types::test_utils::generate_deterministic_keypair; use validator_client::Config as ValidatorClientConfig; fn main() { @@ -29,6 +30,21 @@ fn main() { .version("0.0.1") .author("Sigma Prime "), ) + .subcommand( + SubCommand::with_name("generate_deterministic") + .about("Generates a deterministic validator private key FOR TESTING") + .version("0.0.1") + .author("Sigma Prime ") + .arg( + Arg::with_name("validator index") + .long("index") + .short("i") + .value_name("index") + .help("The index of the validator, for which the test key is generated") + .takes_value(true) + .required(true), + ), + ) .get_matches(); let config = ValidatorClientConfig::parse_args(&matches, &log) @@ -51,6 +67,23 @@ fn main() { key_path.to_string_lossy() ); } + ("generate_deterministic", Some(gen_d_matches)) => { + let validator_index = gen_d_matches + .value_of("validator index") + .expect("Validator index required.") + .parse::() + .expect("Invalid validator index.") as usize; + let keypair = generate_deterministic_keypair(validator_index); + let key_path: PathBuf = config + .save_key(&keypair) + .expect("Unable to save newly generated deterministic private key."); + debug!( + log, + "Deterministic Keypair generated {:?}, saved to: {:?}", + keypair.identifier(), + key_path.to_string_lossy() + ); + } _ => panic!( "The account manager must be run with a subcommand. See help for more information." ), diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index 55d4bacfd..34b6e11c6 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Paul Hauner ", "Age Manning { +pub struct BeaconChain { pub block_store: Arc>, pub state_store: Arc>, pub slot_clock: U, - pub op_pool: OperationPool, - canonical_head: RwLock, - finalized_head: RwLock, - pub state: RwLock, + pub op_pool: OperationPool, + canonical_head: RwLock>, + finalized_head: RwLock>, + pub state: RwLock>, pub spec: ChainSpec, pub fork_choice: RwLock, } -impl BeaconChain +impl BeaconChain where T: ClientDB, U: SlotClock, F: ForkChoice, + E: EthSpec, { /// Instantiate a new Beacon Chain, from genesis. pub fn from_genesis( state_store: Arc>, block_store: Arc>, slot_clock: U, - mut genesis_state: BeaconState, + mut genesis_state: BeaconState, genesis_block: BeaconBlock, spec: ChainSpec, fork_choice: F, @@ -190,7 +191,6 @@ where count: usize, skip: usize, ) -> Result, Error> { - let spec = &self.spec; let step_by = Slot::from(skip + 1); let mut roots: Vec = vec![]; @@ -218,7 +218,7 @@ where // // If we get `SlotOutOfBounds` error, load the oldest available historic // state from the DB. - match state.get_block_root(slot, spec) { + match state.get_block_root(slot) { Ok(root) => { if slot < earliest_slot { break; @@ -230,9 +230,9 @@ where Err(BeaconStateError::SlotOutOfBounds) => { // Read the earliest historic state in the current slot. let earliest_historic_slot = - state.slot - Slot::from(spec.slots_per_historical_root); + state.slot - Slot::from(E::SlotsPerHistoricalRoot::to_usize()); // Load the earlier state from disk. - let new_state_root = state.get_state_root(earliest_historic_slot, spec)?; + let new_state_root = state.get_state_root(earliest_historic_slot)?; // Break if the DB is unable to load the state. state = match self.state_store.get_deserialized(&new_state_root) { @@ -270,7 +270,7 @@ where &self, new_beacon_block: BeaconBlock, new_beacon_block_root: Hash256, - new_beacon_state: BeaconState, + new_beacon_state: BeaconState, new_beacon_state_root: Hash256, ) { debug!( @@ -292,7 +292,7 @@ where /// It is important to note that the `beacon_state` returned may not match the present slot. It /// is the state as it was when the head block was received, which could be some slots prior to /// now. - pub fn head(&self) -> RwLockReadGuard { + pub fn head(&self) -> RwLockReadGuard> { self.canonical_head.read() } @@ -302,9 +302,7 @@ where /// state and calling `catchup_state` as it will not result in an old state being installed and /// then having it iteratively updated -- in such a case it's possible for another thread to /// find the state at an old slot. - pub fn update_state(&self, mut state: BeaconState) -> Result<(), Error> { - let latest_block_header = self.head().beacon_block.block_header(); - + pub fn update_state(&self, mut state: BeaconState) -> Result<(), Error> { let present_slot = match self.slot_clock.present_slot() { Ok(Some(slot)) => slot, _ => return Err(Error::UnableToReadSlot), @@ -312,7 +310,7 @@ where // If required, transition the new state to the present slot. for _ in state.slot.as_u64()..present_slot.as_u64() { - per_slot_processing(&mut state, &latest_block_header, &self.spec)?; + per_slot_processing(&mut state, &self.spec)?; } state.build_all_caches(&self.spec)?; @@ -324,8 +322,6 @@ where /// Ensures the current canonical `BeaconState` has been transitioned to match the `slot_clock`. pub fn catchup_state(&self) -> Result<(), Error> { - let latest_block_header = self.head().beacon_block.block_header(); - let present_slot = match self.slot_clock.present_slot() { Ok(Some(slot)) => slot, _ => return Err(Error::UnableToReadSlot), @@ -339,7 +335,7 @@ where state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &self.spec)?; state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &self.spec)?; - per_slot_processing(&mut *state, &latest_block_header, &self.spec)?; + per_slot_processing(&mut *state, &self.spec)?; } state.build_all_caches(&self.spec)?; @@ -361,7 +357,7 @@ where &self, new_beacon_block: BeaconBlock, new_beacon_block_root: Hash256, - new_beacon_state: BeaconState, + new_beacon_state: BeaconState, new_beacon_state_root: Hash256, ) { let mut finalized_head = self.finalized_head.write(); @@ -375,7 +371,7 @@ where /// Returns a read-lock guarded `CheckPoint` struct for reading the justified head (as chosen, /// indirectly, by the fork-choice rule). - pub fn finalized_head(&self) -> RwLockReadGuard { + pub fn finalized_head(&self) -> RwLockReadGuard> { self.finalized_head.read() } @@ -497,17 +493,14 @@ where } else { // If the current head block is not from this slot, use the slot from the previous // epoch. - *self.state.read().get_block_root( - current_epoch_start_slot - self.spec.slots_per_epoch, - &self.spec, - )? + *self + .state + .read() + .get_block_root(current_epoch_start_slot - self.spec.slots_per_epoch)? } } else { // If we're not on the first slot of the epoch. - *self - .state - .read() - .get_block_root(current_epoch_start_slot, &self.spec)? + *self.state.read().get_block_root(current_epoch_start_slot)? }; Ok(AttestationData { @@ -617,9 +610,8 @@ where // Transition the parent state to the block slot. let mut state = parent_state; - let previous_block_header = parent_block.block_header(); for _ in state.slot.as_u64()..block.slot.as_u64() { - if let Err(e) = per_slot_processing(&mut state, &previous_block_header, &self.spec) { + if let Err(e) = per_slot_processing(&mut state, &self.spec) { return Ok(BlockProcessingOutcome::InvalidBlock( InvalidBlock::SlotProcessingError(e), )); @@ -672,7 +664,7 @@ where pub fn produce_block( &self, randao_reveal: Signature, - ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { + ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { debug!("Producing block at slot {}...", self.state.read().slot); let mut state = self.state.read().clone(); @@ -682,7 +674,7 @@ where trace!("Finding attestations for new block..."); let previous_block_root = *state - .get_block_root(state.slot - 1, &self.spec) + .get_block_root(state.slot - 1) .map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?; let (proposer_slashings, attester_slashings) = @@ -767,7 +759,7 @@ where /// /// This could be a very expensive operation and should only be done in testing/analysis /// activities. - pub fn chain_dump(&self) -> Result, Error> { + pub fn chain_dump(&self) -> Result>, Error> { let mut dump = vec![]; let mut last_slot = CheckPoint { diff --git a/beacon_node/beacon_chain/src/checkpoint.rs b/beacon_node/beacon_chain/src/checkpoint.rs index 78227e5c8..c069ac104 100644 --- a/beacon_node/beacon_chain/src/checkpoint.rs +++ b/beacon_node/beacon_chain/src/checkpoint.rs @@ -1,22 +1,22 @@ use serde_derive::Serialize; -use types::{BeaconBlock, BeaconState, Hash256}; +use types::{BeaconBlock, BeaconState, EthSpec, Hash256}; /// Represents some block and it's associated state. Generally, this will be used for tracking the /// head, justified head and finalized head. #[derive(Clone, Serialize, PartialEq, Debug)] -pub struct CheckPoint { +pub struct CheckPoint { pub beacon_block: BeaconBlock, pub beacon_block_root: Hash256, - pub beacon_state: BeaconState, + pub beacon_state: BeaconState, pub beacon_state_root: Hash256, } -impl CheckPoint { +impl CheckPoint { /// Create a new checkpoint. pub fn new( beacon_block: BeaconBlock, beacon_block_root: Hash256, - beacon_state: BeaconState, + beacon_state: BeaconState, beacon_state_root: Hash256, ) -> Self { Self { @@ -32,7 +32,7 @@ impl CheckPoint { &mut self, beacon_block: BeaconBlock, beacon_block_root: Hash256, - beacon_state: BeaconState, + beacon_state: BeaconState, beacon_state_root: Hash256, ) { self.beacon_block = beacon_block; diff --git a/beacon_node/beacon_chain/src/initialise.rs b/beacon_node/beacon_chain/src/initialise.rs index 0951e06fb..83b60a4f7 100644 --- a/beacon_node/beacon_chain/src/initialise.rs +++ b/beacon_node/beacon_chain/src/initialise.rs @@ -7,18 +7,25 @@ use db::stores::{BeaconBlockStore, BeaconStateStore}; use db::{DiskDB, MemoryDB}; use fork_choice::BitwiseLMDGhost; use slot_clock::SystemTimeSlotClock; -use ssz::TreeHash; use std::path::PathBuf; use std::sync::Arc; +use tree_hash::TreeHash; use types::test_utils::TestingBeaconStateBuilder; -use types::{BeaconBlock, ChainSpec, Hash256}; +use types::{BeaconBlock, ChainSpec, FewValidatorsEthSpec, FoundationEthSpec, Hash256}; //TODO: Correct this for prod //TODO: Account for historical db pub fn initialise_beacon_chain( spec: &ChainSpec, db_name: Option<&PathBuf>, -) -> Arc>> { +) -> Arc< + BeaconChain< + DiskDB, + SystemTimeSlotClock, + BitwiseLMDGhost, + FoundationEthSpec, + >, +> { // set up the db let db = Arc::new(DiskDB::open( db_name.expect("Database directory must be included"), @@ -32,7 +39,7 @@ pub fn initialise_beacon_chain( let (genesis_state, _keypairs) = state_builder.build(); let mut genesis_block = BeaconBlock::empty(&spec); - genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); + genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root()); // Slot clock let slot_clock = SystemTimeSlotClock::new( @@ -64,7 +71,14 @@ pub fn initialise_beacon_chain( pub fn initialise_test_beacon_chain( spec: &ChainSpec, _db_name: Option<&PathBuf>, -) -> Arc>> { +) -> Arc< + BeaconChain< + MemoryDB, + SystemTimeSlotClock, + BitwiseLMDGhost, + FewValidatorsEthSpec, + >, +> { let db = Arc::new(MemoryDB::open()); let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone())); @@ -73,7 +87,7 @@ pub fn initialise_test_beacon_chain( let (genesis_state, _keypairs) = state_builder.build(); let mut genesis_block = BeaconBlock::empty(spec); - genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); + genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root()); // Slot clock let slot_clock = SystemTimeSlotClock::new( diff --git a/beacon_node/beacon_chain/src/test_utils/testing_beacon_chain_builder.rs b/beacon_node/beacon_chain/src/test_utils/testing_beacon_chain_builder.rs index 5c5477e55..f7ff3cdae 100644 --- a/beacon_node/beacon_chain/src/test_utils/testing_beacon_chain_builder.rs +++ b/beacon_node/beacon_chain/src/test_utils/testing_beacon_chain_builder.rs @@ -5,19 +5,20 @@ use db::{ }; use fork_choice::BitwiseLMDGhost; use slot_clock::TestingSlotClock; -use ssz::TreeHash; use std::sync::Arc; -use types::test_utils::TestingBeaconStateBuilder; +use tree_hash::TreeHash; use types::*; +use types::{test_utils::TestingBeaconStateBuilder, EthSpec, FewValidatorsEthSpec}; -type TestingBeaconChain = BeaconChain>; +type TestingBeaconChain = + BeaconChain, E>; -pub struct TestingBeaconChainBuilder { - state_builder: TestingBeaconStateBuilder, +pub struct TestingBeaconChainBuilder { + state_builder: TestingBeaconStateBuilder, } -impl TestingBeaconChainBuilder { - pub fn build(self, spec: &ChainSpec) -> TestingBeaconChain { +impl TestingBeaconChainBuilder { + pub fn build(self, spec: &ChainSpec) -> TestingBeaconChain { let db = Arc::new(MemoryDB::open()); let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone())); @@ -27,7 +28,7 @@ impl TestingBeaconChainBuilder { let (genesis_state, _keypairs) = self.state_builder.build(); let mut genesis_block = BeaconBlock::empty(&spec); - genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); + genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root()); // Create the Beacon Chain BeaconChain::from_genesis( @@ -43,8 +44,8 @@ impl TestingBeaconChainBuilder { } } -impl From for TestingBeaconChainBuilder { - fn from(state_builder: TestingBeaconStateBuilder) -> TestingBeaconChainBuilder { +impl From> for TestingBeaconChainBuilder { + fn from(state_builder: TestingBeaconStateBuilder) -> TestingBeaconChainBuilder { TestingBeaconChainBuilder { state_builder } } } diff --git a/beacon_node/beacon_chain/test_harness/Cargo.toml b/beacon_node/beacon_chain/test_harness/Cargo.toml deleted file mode 100644 index 50d154732..000000000 --- a/beacon_node/beacon_chain/test_harness/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "test_harness" -version = "0.1.0" -authors = ["Paul Hauner "] -edition = "2018" - -[[bin]] -name = "test_harness" -path = "src/bin.rs" - -[lib] -name = "test_harness" -path = "src/lib.rs" - -[dev-dependencies] -state_processing = { path = "../../../eth2/state_processing" } - -[dependencies] -attester = { path = "../../../eth2/attester" } -beacon_chain = { path = "../../beacon_chain" } -block_proposer = { path = "../../../eth2/block_proposer" } -bls = { path = "../../../eth2/utils/bls" } -boolean-bitfield = { path = "../../../eth2/utils/boolean-bitfield" } -clap = "2.32.0" -db = { path = "../../db" } -parking_lot = "0.7" -failure = "0.1" -failure_derive = "0.1" -fork_choice = { path = "../../../eth2/fork_choice" } -hashing = { path = "../../../eth2/utils/hashing" } -int_to_bytes = { path = "../../../eth2/utils/int_to_bytes" } -log = "0.4" -env_logger = "0.6.0" -rayon = "1.0" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" -serde_yaml = "0.8" -slot_clock = { path = "../../../eth2/utils/slot_clock" } -ssz = { path = "../../../eth2/utils/ssz" } -types = { path = "../../../eth2/types" } -yaml-rust = "0.4.2" diff --git a/beacon_node/beacon_chain/test_harness/README.md b/beacon_node/beacon_chain/test_harness/README.md deleted file mode 100644 index 9dfd90d60..000000000 --- a/beacon_node/beacon_chain/test_harness/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# Test Harness - -Provides a testing environment for the `BeaconChain`, `Attester` and `BlockProposer` objects. - -This environment bypasses networking and client run-times and connects the `Attester` and `Proposer` -directly to the `BeaconChain` via an `Arc`. - -The `BeaconChainHarness` contains a single `BeaconChain` instance and many `ValidatorHarness` -instances. All of the `ValidatorHarness` instances work to advance the `BeaconChain` by -producing blocks and attestations. - -The crate consists of a library and binary, examples for using both are -described below. - -## YAML - -Both the library and the binary are capable of parsing tests from a YAML file, -in fact this is the sole purpose of the binary. - -You can find YAML test cases [here](specs/). An example is included below: - -```yaml -title: Validator Registry Tests -summary: Tests deposit and slashing effects on validator registry. -test_suite: validator_registry -fork: tchaikovsky -version: 1.0 -test_cases: - - config: - slots_per_epoch: 64 - deposits_for_chain_start: 1000 - num_slots: 64 - skip_slots: [2, 3] - deposits: - # At slot 1, create a new validator deposit of 32 ETH. - - slot: 1 - amount: 32 - # Trigger more deposits... - - slot: 3 - amount: 32 - - slot: 5 - amount: 32 - proposer_slashings: - # At slot 2, trigger a proposer slashing for validator #42. - - slot: 2 - validator_index: 42 - # Trigger another slashing... - - slot: 8 - validator_index: 13 - attester_slashings: - # At slot 2, trigger an attester slashing for validators #11 and #12. - - slot: 2 - validator_indices: [11, 12] - # Trigger another slashing... - - slot: 5 - validator_indices: [14] - results: - num_skipped_slots: 2 - states: - - slot: 63 - num_validators: 1003 - slashed_validators: [11, 12, 13, 14, 42] - exited_validators: [] - -``` - -Thanks to [prsym](http://github.com/prysmaticlabs/prysm) for coming up with the -base YAML format. - -### Notes - -Wherever `slot` is used, it is actually the "slot height", or slots since -genesis. This allows the tests to disregard the `GENESIS_EPOCH`. - -### Differences from Prysmatic's format - -1. The detail for `deposits`, `proposer_slashings` and `attester_slashings` is - ommitted from the test specification. It assumed they should be valid - objects. -2. There is a `states` list in `results` that runs checks against any state - specified by a `slot` number. This is in contrast to the variables in - `results` that assume the last (highest) state should be inspected. - -#### Reasoning - -Respective reasonings for above changes: - -1. This removes the concerns of the actual object structure from the tests. - This allows for more variation in the deposits/slashings objects without - needing to update the tests. Also, it makes it makes it easier to create - tests. -2. This gives more fine-grained control over the tests. It allows for checking - that certain events happened at certain times whilst making the tests only - slightly more verbose. - -_Notes: it may be useful to add an extra field to each slashing type to -indicate if it should be valid or not. It also may be useful to add an option -for double-vote/surround-vote attester slashings. The `amount` field was left -on `deposits` as it changes the behaviour of state significantly._ - -## Binary Usage Example - -Follow these steps to run as a binary: - -1. Navigate to the root of this crate (where this readme is located) -2. Run `$ cargo run --release -- --yaml examples/validator_registry.yaml` - -_Note: the `--release` flag builds the binary without all the debugging -instrumentation. The test is much faster built using `--release`. As is -customary in cargo, the flags before `--` are passed to cargo and the flags -after are passed to the binary._ - -### CLI Options - -``` -Lighthouse Test Harness Runner 0.0.1 -Sigma Prime -Runs `test_harness` using a YAML test_case. - -USAGE: - test_harness --log-level --yaml - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - --log-level Logging level. [default: debug] [possible values: error, warn, info, debug, trace] - --yaml YAML file test_case. -``` - - -## Library Usage Example - -```rust -use test_harness::BeaconChainHarness; -use types::ChainSpec; - -let validator_count = 8; -let spec = ChainSpec::few_validators(); - -let mut harness = BeaconChainHarness::new(spec, validator_count); - -harness.advance_chain_with_block(); - -let chain = harness.chain_dump().unwrap(); - -// One block should have been built on top of the genesis block. -assert_eq!(chain.len(), 2); -``` diff --git a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml b/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml deleted file mode 100644 index ad9c899cf..000000000 --- a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml +++ /dev/null @@ -1,63 +0,0 @@ -title: Validator Registry Tests -summary: Tests deposit and slashing effects on validator registry. -test_suite: validator_registry -fork: tchaikovsky -version: 1.0 -test_cases: - - config: - slots_per_epoch: 64 - deposits_for_chain_start: 1000 - num_slots: 64 - skip_slots: [2, 3] - persistent_committee_period: 0 - deposits: - # At slot 1, create a new validator deposit of 5 ETH. - - slot: 1 - amount: 5000000000 - # Trigger more deposits... - - slot: 3 - amount: 5000000000 - - slot: 5 - amount: 32000000000 - exits: - # At slot 10, submit an exit for validator #50. - - slot: 10 - validator_index: 50 - transfers: - - slot: 6 - from: 1000 - to: 1001 - amount: 5000000000 - proposer_slashings: - # At slot 2, trigger a proposer slashing for validator #42. - - slot: 2 - validator_index: 42 - # Trigger another slashing... - - slot: 8 - validator_index: 13 - attester_slashings: - # At slot 2, trigger an attester slashing for validators #11 and #12. - - slot: 2 - validator_indices: [11, 12] - # Trigger another slashing... - - slot: 5 - validator_indices: [14] - results: - num_skipped_slots: 2 - states: - - slot: 63 - num_validators: 1003 - num_previous_epoch_attestations: 0 - # slots_per_epoch - attestation_inclusion_delay - skip_slots - num_current_epoch_attestations: 57 - slashed_validators: [11, 12, 13, 14, 42] - exited_validators: [] - exit_initiated_validators: [50] - balances: - - validator_index: 1000 - comparison: "eq" - balance: 0 - - validator_index: 1001 - comparison: "eq" - balance: 10000000000 - diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs deleted file mode 100644 index aeb734a4e..000000000 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ /dev/null @@ -1,350 +0,0 @@ -use super::ValidatorHarness; -use beacon_chain::{BeaconChain, BlockProcessingOutcome}; -pub use beacon_chain::{BeaconChainError, CheckPoint}; -use db::{ - stores::{BeaconBlockStore, BeaconStateStore}, - MemoryDB, -}; -use fork_choice::BitwiseLMDGhost; -use log::debug; -use rayon::prelude::*; -use slot_clock::TestingSlotClock; -use ssz::TreeHash; -use std::sync::Arc; -use types::{test_utils::TestingBeaconStateBuilder, *}; - -type TestingBeaconChain = BeaconChain>; - -/// The beacon chain harness simulates a single beacon node with `validator_count` validators connected -/// to it. Each validator is provided a borrow to the beacon chain, where it may read -/// information and submit blocks/attestations for processing. -/// -/// This test harness is useful for testing validator and internal state transition logic. It -/// is not useful for testing that multiple beacon nodes can reach consensus. -pub struct BeaconChainHarness { - pub db: Arc, - pub beacon_chain: Arc, - pub block_store: Arc>, - pub state_store: Arc>, - pub validators: Vec, - pub spec: Arc, -} - -impl BeaconChainHarness { - /// Create a new harness with: - /// - /// - A keypair, `BlockProducer` and `Attester` for each validator. - /// - A new BeaconChain struct where the given validators are in the genesis. - pub fn new(spec: ChainSpec, validator_count: usize) -> Self { - let state_builder = - TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, &spec); - Self::from_beacon_state_builder(state_builder, spec) - } - - pub fn from_beacon_state_builder( - state_builder: TestingBeaconStateBuilder, - spec: ChainSpec, - ) -> Self { - let db = Arc::new(MemoryDB::open()); - let block_store = Arc::new(BeaconBlockStore::new(db.clone())); - let state_store = Arc::new(BeaconStateStore::new(db.clone())); - let slot_clock = TestingSlotClock::new(spec.genesis_slot.as_u64()); - let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); - - let (mut genesis_state, keypairs) = state_builder.build(); - - let mut genesis_block = BeaconBlock::empty(&spec); - genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); - - genesis_state - .build_epoch_cache(RelativeEpoch::Previous, &spec) - .unwrap(); - genesis_state - .build_epoch_cache(RelativeEpoch::Current, &spec) - .unwrap(); - genesis_state - .build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &spec) - .unwrap(); - genesis_state - .build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &spec) - .unwrap(); - - // Create the Beacon Chain - let beacon_chain = Arc::new( - BeaconChain::from_genesis( - state_store.clone(), - block_store.clone(), - slot_clock, - genesis_state, - genesis_block, - spec.clone(), - fork_choice, - ) - .unwrap(), - ); - - let spec = Arc::new(spec); - - debug!("Creating validator producer and attester instances..."); - - // Spawn the test validator instances. - let validators: Vec = keypairs - .iter() - .map(|keypair| { - ValidatorHarness::new(keypair.clone(), beacon_chain.clone(), spec.clone()) - }) - .collect(); - - debug!("Created {} ValidatorHarnesss", validators.len()); - - Self { - db, - beacon_chain, - block_store, - state_store, - validators, - spec, - } - } - - /// Move the `slot_clock` for the `BeaconChain` forward one slot. - /// - /// This is the equivalent of advancing a system clock forward one `SLOT_DURATION`. - /// - /// Returns the new slot. - pub fn increment_beacon_chain_slot(&mut self) -> Slot { - let slot = self.beacon_chain.present_slot() + 1; - - let nth_slot = slot - - slot - .epoch(self.spec.slots_per_epoch) - .start_slot(self.spec.slots_per_epoch); - let nth_epoch = slot.epoch(self.spec.slots_per_epoch) - self.spec.genesis_epoch; - debug!( - "Advancing BeaconChain to slot {}, epoch {} (epoch height: {}, slot {} in epoch.).", - slot, - slot.epoch(self.spec.slots_per_epoch), - nth_epoch, - nth_slot - ); - - self.beacon_chain.slot_clock.set_slot(slot.as_u64()); - self.beacon_chain - .catchup_state() - .expect("Failed to catch state"); - slot - } - - pub fn gather_attesations(&mut self) -> Vec { - let present_slot = self.beacon_chain.present_slot(); - let state = self.beacon_chain.state.read(); - - let mut attestations = vec![]; - - for committee in state - .get_crosslink_committees_at_slot(present_slot, &self.spec) - .unwrap() - { - for &validator in &committee.committee { - let duties = state - .get_attestation_duties(validator, &self.spec) - .unwrap() - .expect("Attesting validators by definition have duties"); - - // Obtain `AttestationData` from the beacon chain. - let data = self - .beacon_chain - .produce_attestation_data(duties.shard) - .unwrap(); - - // Produce an aggregate signature with a single signature. - let aggregate_signature = { - let message = AttestationDataAndCustodyBit { - data: data.clone(), - custody_bit: false, - } - .hash_tree_root(); - let domain = self.spec.get_domain( - state.slot.epoch(self.spec.slots_per_epoch), - Domain::Attestation, - &state.fork, - ); - let sig = - Signature::new(&message, domain, &self.validators[validator].keypair.sk); - - let mut agg_sig = AggregateSignature::new(); - agg_sig.add(&sig); - - agg_sig - }; - - let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); - let custody_bitfield = Bitfield::with_capacity(duties.committee_len); - - aggregation_bitfield.set(duties.committee_index, true); - - attestations.push(Attestation { - aggregation_bitfield, - data, - custody_bitfield, - aggregate_signature, - }) - } - } - - attestations - } - - /// Get the block from the proposer for the slot. - /// - /// Note: the validator will only produce it _once per slot_. So, if you call this twice you'll - /// only get a block once. - pub fn produce_block(&mut self) -> BeaconBlock { - let present_slot = self.beacon_chain.present_slot(); - - let proposer = self.beacon_chain.block_proposer(present_slot).unwrap(); - - debug!( - "Producing block from validator #{} for slot {}.", - proposer, present_slot - ); - - // Ensure the validators slot clock is accurate. - self.validators[proposer].set_slot(present_slot); - - self.validators[proposer].produce_block().unwrap() - } - - /// Advances the chain with a BeaconBlock and attestations from all validators. - /// - /// This is the ideal scenario for the Beacon Chain, 100% honest participation from - /// validators. - pub fn advance_chain_with_block(&mut self) -> BeaconBlock { - self.increment_beacon_chain_slot(); - - // Produce a new block. - let block = self.produce_block(); - debug!("Submitting block for processing..."); - match self.beacon_chain.process_block(block.clone()) { - Ok(BlockProcessingOutcome::ValidBlock(_)) => {} - other => panic!("block processing failed with {:?}", other), - }; - debug!("...block processed by BeaconChain."); - - debug!("Producing attestations..."); - - // Produce new attestations. - let attestations = self.gather_attesations(); - - debug!("Processing {} attestations...", attestations.len()); - - attestations - .par_iter() - .enumerate() - .for_each(|(i, attestation)| { - self.beacon_chain - .process_attestation(attestation.clone()) - .unwrap_or_else(|_| panic!("Attestation {} invalid: {:?}", i, attestation)); - }); - - debug!("Attestations processed."); - - block - } - - /// Signs a message using some validators secret key with the `Fork` info from the latest state - /// of the `BeaconChain`. - /// - /// Useful for producing slashable messages and other objects that `BeaconChainHarness` does - /// not produce naturally. - pub fn validator_sign( - &self, - validator_index: usize, - message: &[u8], - epoch: Epoch, - domain_type: Domain, - ) -> Option { - let validator = self.validators.get(validator_index)?; - - let domain = self - .spec - .get_domain(epoch, domain_type, &self.beacon_chain.state.read().fork); - - Some(Signature::new(message, domain, &validator.keypair.sk)) - } - - /// Returns the current `Fork` of the `beacon_chain`. - pub fn fork(&self) -> Fork { - self.beacon_chain.state.read().fork.clone() - } - - /// Returns the current `epoch` of the `beacon_chain`. - pub fn epoch(&self) -> Epoch { - self.beacon_chain - .state - .read() - .slot - .epoch(self.spec.slots_per_epoch) - } - - /// Returns the keypair for some validator index. - pub fn validator_keypair(&self, validator_index: usize) -> Option<&Keypair> { - self.validators - .get(validator_index) - .and_then(|v| Some(&v.keypair)) - } - - /// Submit a deposit to the `BeaconChain` and, if given a keypair, create a new - /// `ValidatorHarness` instance for this validator. - /// - /// If a new `ValidatorHarness` was created, the validator should become fully operational as - /// if the validator were created during `BeaconChainHarness` instantiation. - pub fn add_deposit(&mut self, deposit: Deposit, keypair: Option) { - self.beacon_chain.process_deposit(deposit).unwrap(); - - // If a keypair is present, add a new `ValidatorHarness` to the rig. - if let Some(keypair) = keypair { - let validator = - ValidatorHarness::new(keypair, self.beacon_chain.clone(), self.spec.clone()); - self.validators.push(validator); - } - } - - /// Submit an exit to the `BeaconChain` for inclusion in some block. - /// - /// Note: the `ValidatorHarness` for this validator continues to exist. Once it is exited it - /// will stop receiving duties from the beacon chain and just do nothing when prompted to - /// produce/attest. - pub fn add_exit(&mut self, exit: VoluntaryExit) { - self.beacon_chain.process_voluntary_exit(exit).unwrap(); - } - - /// Submit an transfer to the `BeaconChain` for inclusion in some block. - pub fn add_transfer(&mut self, transfer: Transfer) { - self.beacon_chain.process_transfer(transfer).unwrap(); - } - - /// Submit a proposer slashing to the `BeaconChain` for inclusion in some block. - pub fn add_proposer_slashing(&mut self, proposer_slashing: ProposerSlashing) { - self.beacon_chain - .process_proposer_slashing(proposer_slashing) - .unwrap(); - } - - /// Submit an attester slashing to the `BeaconChain` for inclusion in some block. - pub fn add_attester_slashing(&mut self, attester_slashing: AttesterSlashing) { - self.beacon_chain - .process_attester_slashing(attester_slashing) - .unwrap(); - } - - /// Executes the fork choice rule on the `BeaconChain`, selecting a new canonical head. - pub fn run_fork_choice(&mut self) { - self.beacon_chain.fork_choice().unwrap() - } - - /// Dump all blocks and states from the canonical beacon chain. - pub fn chain_dump(&self) -> Result, BeaconChainError> { - self.beacon_chain.chain_dump() - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/bin.rs b/beacon_node/beacon_chain/test_harness/src/bin.rs deleted file mode 100644 index 3afc921de..000000000 --- a/beacon_node/beacon_chain/test_harness/src/bin.rs +++ /dev/null @@ -1,102 +0,0 @@ -use clap::{App, Arg, SubCommand}; -use env_logger::{Builder, Env}; -use gen_keys::gen_keys; -use run_test::run_test; -use std::fs; -use types::test_utils::keypairs_path; -use types::ChainSpec; - -mod beacon_chain_harness; -mod gen_keys; -mod run_test; -mod test_case; -mod validator_harness; - -use validator_harness::ValidatorHarness; - -fn main() { - let validator_file_path = keypairs_path(); - - let _ = fs::create_dir(validator_file_path.parent().unwrap()); - - let matches = App::new("Lighthouse Test Harness Runner") - .version("0.0.1") - .author("Sigma Prime ") - .about("Runs `test_harness` using a YAML test_case.") - .arg( - Arg::with_name("log") - .long("log-level") - .short("l") - .value_name("LOG_LEVEL") - .help("Logging level.") - .possible_values(&["error", "warn", "info", "debug", "trace"]) - .default_value("debug") - .required(true), - ) - .arg( - Arg::with_name("spec") - .long("spec") - .short("s") - .value_name("SPECIFICATION") - .help("ChainSpec instantiation.") - .possible_values(&["foundation", "few_validators"]) - .default_value("foundation"), - ) - .subcommand( - SubCommand::with_name("run_test") - .about("Executes a YAML test specification") - .arg( - Arg::with_name("yaml") - .long("yaml") - .value_name("FILE") - .help("YAML file test_case.") - .required(true), - ) - .arg( - Arg::with_name("validators_dir") - .long("validators-dir") - .short("v") - .value_name("VALIDATORS_DIR") - .help("A directory with validator deposits and keypair YAML."), - ), - ) - .subcommand( - SubCommand::with_name("gen_keys") - .about("Builds a file of BLS keypairs for faster tests.") - .arg( - Arg::with_name("validator_count") - .long("validator_count") - .short("n") - .value_name("VALIDATOR_COUNT") - .help("Number of validators to generate.") - .required(true), - ) - .arg( - Arg::with_name("output_file") - .long("output_file") - .short("d") - .value_name("GENESIS_TIME") - .help("Output directory for generated YAML.") - .default_value(validator_file_path.to_str().unwrap()), - ), - ) - .get_matches(); - - if let Some(log_level) = matches.value_of("log") { - Builder::from_env(Env::default().default_filter_or(log_level)).init(); - } - - let _spec = match matches.value_of("spec") { - Some("foundation") => ChainSpec::foundation(), - Some("few_validators") => ChainSpec::few_validators(), - _ => unreachable!(), // Has a default value, should always exist. - }; - - if let Some(matches) = matches.subcommand_matches("run_test") { - run_test(matches); - } - - if let Some(matches) = matches.subcommand_matches("gen_keys") { - gen_keys(matches); - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/gen_keys.rs b/beacon_node/beacon_chain/test_harness/src/gen_keys.rs deleted file mode 100644 index abd512423..000000000 --- a/beacon_node/beacon_chain/test_harness/src/gen_keys.rs +++ /dev/null @@ -1,21 +0,0 @@ -use clap::{value_t, ArgMatches}; -use log::debug; -use std::path::Path; -use types::test_utils::{generate_deterministic_keypairs, KeypairsFile}; - -/// Creates a file containing BLS keypairs. -pub fn gen_keys(matches: &ArgMatches) { - let validator_count = value_t!(matches.value_of("validator_count"), usize) - .expect("Validator count is required argument"); - let output_file = matches - .value_of("output_file") - .expect("Output file has a default value."); - - let keypairs = generate_deterministic_keypairs(validator_count); - - debug!("Writing keypairs to file..."); - - let keypairs_path = Path::new(output_file); - - keypairs.to_raw_file(&keypairs_path, &keypairs).unwrap(); -} diff --git a/beacon_node/beacon_chain/test_harness/src/lib.rs b/beacon_node/beacon_chain/test_harness/src/lib.rs deleted file mode 100644 index 0703fd4a5..000000000 --- a/beacon_node/beacon_chain/test_harness/src/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Provides a testing environment for the `BeaconChain`, `Attester` and `BlockProposer` objects. -//! -//! This environment bypasses networking and client run-times and connects the `Attester` and `Proposer` -//! directly to the `BeaconChain` via an `Arc`. -//! -//! The `BeaconChainHarness` contains a single `BeaconChain` instance and many `ValidatorHarness` -//! instances. All of the `ValidatorHarness` instances work to advance the `BeaconChain` by -//! producing blocks and attestations. -//! -//! Example: -//! ``` -//! use test_harness::BeaconChainHarness; -//! use types::ChainSpec; -//! -//! let validator_count = 8; -//! let spec = ChainSpec::few_validators(); -//! -//! let mut harness = BeaconChainHarness::new(spec, validator_count); -//! -//! harness.advance_chain_with_block(); -//! -//! let chain = harness.chain_dump().unwrap(); -//! -//! // One block should have been built on top of the genesis block. -//! assert_eq!(chain.len(), 2); -//! ``` - -mod beacon_chain_harness; -pub mod test_case; -mod validator_harness; - -pub use self::beacon_chain_harness::BeaconChainHarness; -pub use self::validator_harness::ValidatorHarness; diff --git a/beacon_node/beacon_chain/test_harness/src/run_test.rs b/beacon_node/beacon_chain/test_harness/src/run_test.rs deleted file mode 100644 index 4caa299d6..000000000 --- a/beacon_node/beacon_chain/test_harness/src/run_test.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::test_case::TestCase; -use clap::ArgMatches; -use std::{fs::File, io::prelude::*}; -use yaml_rust::YamlLoader; - -/// Runs a YAML-specified test case. -pub fn run_test(matches: &ArgMatches) { - if let Some(yaml_file) = matches.value_of("yaml") { - let docs = { - let mut file = File::open(yaml_file).unwrap(); - - let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); - - YamlLoader::load_from_str(&yaml_str).unwrap() - }; - - for doc in &docs { - // For each `test_cases` YAML in the document, build a `TestCase`, execute it and - // assert that the execution result matches the test_case description. - // - // In effect, for each `test_case` a new `BeaconChainHarness` is created from genesis - // and a new `BeaconChain` is built as per the test_case. - // - // After the `BeaconChain` has been built out as per the test_case, a dump of all blocks - // and states in the chain is obtained and checked against the `results` specified in - // the `test_case`. - // - // If any of the expectations in the results are not met, the process - // panics with a message. - for test_case in doc["test_cases"].as_vec().unwrap() { - let test_case = TestCase::from_yaml(test_case); - test_case.assert_result_valid(test_case.execute()) - } - } - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/test_case.rs b/beacon_node/beacon_chain/test_harness/src/test_case.rs deleted file mode 100644 index f65b45505..000000000 --- a/beacon_node/beacon_chain/test_harness/src/test_case.rs +++ /dev/null @@ -1,312 +0,0 @@ -//! Defines execution and testing specs for a `BeaconChainHarness` instance. Supports loading from -//! a YAML file. - -use crate::beacon_chain_harness::BeaconChainHarness; -use beacon_chain::CheckPoint; -use log::{info, warn}; -use ssz::SignedRoot; -use types::*; - -use types::test_utils::*; -use yaml_rust::Yaml; - -mod config; -mod results; -mod state_check; -mod yaml_helpers; - -pub use config::Config; -pub use results::Results; -pub use state_check::StateCheck; - -/// Defines the execution and testing of a `BeaconChainHarness` instantiation. -/// -/// Typical workflow is: -/// -/// 1. Instantiate the `TestCase` from YAML: `let test_case = TestCase::from_yaml(&my_yaml);` -/// 2. Execute the test_case: `let result = test_case.execute();` -/// 3. Test the results against the test_case: `test_case.assert_result_valid(result);` -#[derive(Debug)] -pub struct TestCase { - /// Defines the execution. - pub config: Config, - /// Defines tests to run against the execution result. - pub results: Results, -} - -/// The result of executing a `TestCase`. -/// -pub struct ExecutionResult { - /// The canonical beacon chain generated from the execution. - pub chain: Vec, - /// The spec used for execution. - pub spec: ChainSpec, -} - -impl TestCase { - /// Load the test case from a YAML document. - pub fn from_yaml(test_case: &Yaml) -> Self { - Self { - results: Results::from_yaml(&test_case["results"]), - config: Config::from_yaml(&test_case["config"]), - } - } - - /// Return a `ChainSpec::foundation()`. - /// - /// If specified in `config`, returns it with a modified `slots_per_epoch`. - fn spec(&self) -> ChainSpec { - let mut spec = ChainSpec::foundation(); - - if let Some(n) = self.config.slots_per_epoch { - spec.slots_per_epoch = n; - } - - if let Some(n) = self.config.persistent_committee_period { - spec.persistent_committee_period = n; - } - - spec - } - - /// Executes the test case, returning an `ExecutionResult`. - #[allow(clippy::cyclomatic_complexity)] - pub fn execute(&self) -> ExecutionResult { - let spec = self.spec(); - let validator_count = self.config.deposits_for_chain_start; - let slots = self.config.num_slots; - - info!( - "Building BeaconChainHarness with {} validators...", - validator_count - ); - - let mut harness = BeaconChainHarness::new(spec, validator_count); - - info!("Starting simulation across {} slots...", slots); - - // Start at 1 because genesis counts as a slot. - for slot_height in 1..slots { - // Used to ensure that deposits in the same slot have incremental deposit indices. - let mut deposit_index_offset = 0; - - // Feed deposits to the BeaconChain. - if let Some(ref deposits) = self.config.deposits { - for (slot, amount) in deposits { - if *slot == slot_height { - info!("Including deposit at slot height {}.", slot_height); - let (deposit, keypair) = - build_deposit(&harness, *amount, deposit_index_offset); - harness.add_deposit(deposit, Some(keypair.clone())); - deposit_index_offset += 1; - } - } - } - - // Feed proposer slashings to the BeaconChain. - if let Some(ref slashings) = self.config.proposer_slashings { - for (slot, validator_index) in slashings { - if *slot == slot_height { - info!( - "Including proposer slashing at slot height {} for validator #{}.", - slot_height, validator_index - ); - let slashing = build_proposer_slashing(&harness, *validator_index); - harness.add_proposer_slashing(slashing); - } - } - } - - // Feed attester slashings to the BeaconChain. - if let Some(ref slashings) = self.config.attester_slashings { - for (slot, validator_indices) in slashings { - if *slot == slot_height { - info!( - "Including attester slashing at slot height {} for validators {:?}.", - slot_height, validator_indices - ); - let slashing = - build_double_vote_attester_slashing(&harness, &validator_indices[..]); - harness.add_attester_slashing(slashing); - } - } - } - - // Feed exits to the BeaconChain. - if let Some(ref exits) = self.config.exits { - for (slot, validator_index) in exits { - if *slot == slot_height { - info!( - "Including exit at slot height {} for validator {}.", - slot_height, validator_index - ); - let exit = build_exit(&harness, *validator_index); - harness.add_exit(exit); - } - } - } - - // Feed transfers to the BeaconChain. - if let Some(ref transfers) = self.config.transfers { - for (slot, from, to, amount) in transfers { - if *slot == slot_height { - info!( - "Including transfer at slot height {} from validator {}.", - slot_height, from - ); - let transfer = build_transfer(&harness, *from, *to, *amount); - harness.add_transfer(transfer); - } - } - } - - // Build a block or skip a slot. - match self.config.skip_slots { - Some(ref skip_slots) if skip_slots.contains(&slot_height) => { - warn!("Skipping slot at height {}.", slot_height); - harness.increment_beacon_chain_slot(); - } - _ => { - info!("Producing block at slot height {}.", slot_height); - harness.advance_chain_with_block(); - } - } - } - - harness.run_fork_choice(); - - info!("Test execution complete!"); - - info!("Building chain dump for analysis..."); - - ExecutionResult { - chain: harness.chain_dump().expect("Chain dump failed."), - spec: (*harness.spec).clone(), - } - } - - /// Checks that the `ExecutionResult` is consistent with the specifications in `self.results`. - /// - /// # Panics - /// - /// Panics with a message if any result does not match exepectations. - pub fn assert_result_valid(&self, execution_result: ExecutionResult) { - info!("Verifying test results..."); - let spec = &execution_result.spec; - - if let Some(num_skipped_slots) = self.results.num_skipped_slots { - assert_eq!( - execution_result.chain.len(), - self.config.num_slots as usize - num_skipped_slots, - "actual skipped slots != expected." - ); - info!( - "OK: Chain length is {} ({} skipped slots).", - execution_result.chain.len(), - num_skipped_slots - ); - } - - if let Some(ref state_checks) = self.results.state_checks { - for checkpoint in &execution_result.chain { - let state = &checkpoint.beacon_state; - - for state_check in state_checks { - let adjusted_state_slot = - state.slot - spec.genesis_epoch.start_slot(spec.slots_per_epoch); - - if state_check.slot == adjusted_state_slot { - state_check.assert_valid(state, spec); - } - } - } - } - } -} - -/// Builds a `Deposit` this is valid for the given `BeaconChainHarness` at its next slot. -fn build_transfer( - harness: &BeaconChainHarness, - sender: u64, - recipient: u64, - amount: u64, -) -> Transfer { - let slot = harness.beacon_chain.state.read().slot + 1; - - let mut builder = TestingTransferBuilder::new(sender, recipient, amount, slot); - - let keypair = harness.validator_keypair(sender as usize).unwrap(); - builder.sign(keypair.clone(), &harness.fork(), &harness.spec); - - builder.build() -} - -/// Builds a `Deposit` this is valid for the given `BeaconChainHarness`. -/// -/// `index_offset` is used to ensure that `deposit.index == state.index` when adding multiple -/// deposits. -fn build_deposit( - harness: &BeaconChainHarness, - amount: u64, - index_offset: u64, -) -> (Deposit, Keypair) { - let keypair = Keypair::random(); - - let mut builder = TestingDepositBuilder::new(keypair.pk.clone(), amount); - builder.set_index(harness.beacon_chain.state.read().deposit_index + index_offset); - builder.sign(&keypair, harness.epoch(), &harness.fork(), &harness.spec); - - (builder.build(), keypair) -} - -/// Builds a `VoluntaryExit` this is valid for the given `BeaconChainHarness`. -fn build_exit(harness: &BeaconChainHarness, validator_index: u64) -> VoluntaryExit { - let epoch = harness - .beacon_chain - .state - .read() - .current_epoch(&harness.spec); - - let mut exit = VoluntaryExit { - epoch, - validator_index, - signature: Signature::empty_signature(), - }; - - let message = exit.signed_root(); - - exit.signature = harness - .validator_sign(validator_index as usize, &message[..], epoch, Domain::Exit) - .expect("Unable to sign VoluntaryExit"); - - exit -} - -/// Builds an `AttesterSlashing` for some `validator_indices`. -/// -/// Signs the message using a `BeaconChainHarness`. -fn build_double_vote_attester_slashing( - harness: &BeaconChainHarness, - validator_indices: &[u64], -) -> AttesterSlashing { - let signer = |validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| { - harness - .validator_sign(validator_index as usize, message, epoch, domain) - .expect("Unable to sign AttesterSlashing") - }; - - TestingAttesterSlashingBuilder::double_vote(validator_indices, signer) -} - -/// Builds an `ProposerSlashing` for some `validator_index`. -/// -/// Signs the message using a `BeaconChainHarness`. -fn build_proposer_slashing(harness: &BeaconChainHarness, validator_index: u64) -> ProposerSlashing { - let signer = |validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| { - harness - .validator_sign(validator_index as usize, message, epoch, domain) - .expect("Unable to sign AttesterSlashing") - }; - - TestingProposerSlashingBuilder::double_vote(validator_index, signer, &harness.spec) -} diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/config.rs b/beacon_node/beacon_chain/test_harness/src/test_case/config.rs deleted file mode 100644 index 12d5da2d7..000000000 --- a/beacon_node/beacon_chain/test_harness/src/test_case/config.rs +++ /dev/null @@ -1,135 +0,0 @@ -use super::yaml_helpers::{as_u64, as_usize, as_vec_u64}; -use types::*; -use yaml_rust::Yaml; - -pub type ValidatorIndex = u64; -pub type ValidatorIndices = Vec; -pub type GweiAmount = u64; - -pub type DepositTuple = (SlotHeight, GweiAmount); -pub type ExitTuple = (SlotHeight, ValidatorIndex); -pub type ProposerSlashingTuple = (SlotHeight, ValidatorIndex); -pub type AttesterSlashingTuple = (SlotHeight, ValidatorIndices); -/// (slot_height, from, to, amount) -pub type TransferTuple = (SlotHeight, ValidatorIndex, ValidatorIndex, GweiAmount); - -/// Defines the execution of a `BeaconStateHarness` across a series of slots. -#[derive(Debug)] -pub struct Config { - /// Initial validators. - pub deposits_for_chain_start: usize, - /// Number of slots in an epoch. - pub slots_per_epoch: Option, - /// Affects the number of epochs a validator must be active before they can withdraw. - pub persistent_committee_period: Option, - /// Number of slots to build before ending execution. - pub num_slots: u64, - /// Number of slots that should be skipped due to inactive validator. - pub skip_slots: Option>, - /// Deposits to be included during execution. - pub deposits: Option>, - /// Proposer slashings to be included during execution. - pub proposer_slashings: Option>, - /// Attester slashings to be including during execution. - pub attester_slashings: Option>, - /// Exits to be including during execution. - pub exits: Option>, - /// Transfers to be including during execution. - pub transfers: Option>, -} - -impl Config { - /// Load from a YAML document. - /// - /// Expects to receive the `config` section of the document. - pub fn from_yaml(yaml: &Yaml) -> Self { - Self { - deposits_for_chain_start: as_usize(&yaml, "deposits_for_chain_start") - .expect("Must specify validator count"), - slots_per_epoch: as_u64(&yaml, "slots_per_epoch"), - persistent_committee_period: as_u64(&yaml, "persistent_committee_period"), - num_slots: as_u64(&yaml, "num_slots").expect("Must specify `config.num_slots`"), - skip_slots: as_vec_u64(yaml, "skip_slots"), - deposits: parse_deposits(&yaml), - proposer_slashings: parse_proposer_slashings(&yaml), - attester_slashings: parse_attester_slashings(&yaml), - exits: parse_exits(&yaml), - transfers: parse_transfers(&yaml), - } - } -} - -/// Parse the `transfers` section of the YAML document. -fn parse_transfers(yaml: &Yaml) -> Option> { - let mut tuples = vec![]; - - for exit in yaml["transfers"].as_vec()? { - let slot = as_u64(exit, "slot").expect("Incomplete transfer (slot)"); - let from = as_u64(exit, "from").expect("Incomplete transfer (from)"); - let to = as_u64(exit, "to").expect("Incomplete transfer (to)"); - let amount = as_u64(exit, "amount").expect("Incomplete transfer (amount)"); - - tuples.push((SlotHeight::from(slot), from, to, amount)); - } - - Some(tuples) -} - -/// Parse the `attester_slashings` section of the YAML document. -fn parse_exits(yaml: &Yaml) -> Option> { - let mut tuples = vec![]; - - for exit in yaml["exits"].as_vec()? { - let slot = as_u64(exit, "slot").expect("Incomplete exit (slot)"); - let validator_index = - as_u64(exit, "validator_index").expect("Incomplete exit (validator_index)"); - - tuples.push((SlotHeight::from(slot), validator_index)); - } - - Some(tuples) -} - -/// Parse the `attester_slashings` section of the YAML document. -fn parse_attester_slashings(yaml: &Yaml) -> Option> { - let mut slashings = vec![]; - - for slashing in yaml["attester_slashings"].as_vec()? { - let slot = as_u64(slashing, "slot").expect("Incomplete attester_slashing (slot)"); - let validator_indices = as_vec_u64(slashing, "validator_indices") - .expect("Incomplete attester_slashing (validator_indices)"); - - slashings.push((SlotHeight::from(slot), validator_indices)); - } - - Some(slashings) -} - -/// Parse the `proposer_slashings` section of the YAML document. -fn parse_proposer_slashings(yaml: &Yaml) -> Option> { - let mut slashings = vec![]; - - for slashing in yaml["proposer_slashings"].as_vec()? { - let slot = as_u64(slashing, "slot").expect("Incomplete proposer slashing (slot)_"); - let validator_index = as_u64(slashing, "validator_index") - .expect("Incomplete proposer slashing (validator_index)"); - - slashings.push((SlotHeight::from(slot), validator_index)); - } - - Some(slashings) -} - -/// Parse the `deposits` section of the YAML document. -fn parse_deposits(yaml: &Yaml) -> Option> { - let mut deposits = vec![]; - - for deposit in yaml["deposits"].as_vec()? { - let slot = as_u64(deposit, "slot").expect("Incomplete deposit (slot)"); - let amount = as_u64(deposit, "amount").expect("Incomplete deposit (amount)"); - - deposits.push((SlotHeight::from(slot), amount)) - } - - Some(deposits) -} diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/results.rs b/beacon_node/beacon_chain/test_harness/src/test_case/results.rs deleted file mode 100644 index 596418c0f..000000000 --- a/beacon_node/beacon_chain/test_harness/src/test_case/results.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::state_check::StateCheck; -use super::yaml_helpers::as_usize; -use yaml_rust::Yaml; - -/// A series of tests to be carried out upon an `ExecutionResult`, returned from executing a -/// `TestCase`. -#[derive(Debug)] -pub struct Results { - pub num_skipped_slots: Option, - pub state_checks: Option>, -} - -impl Results { - /// Load from a YAML document. - /// - /// Expects the `results` section of the YAML document. - pub fn from_yaml(yaml: &Yaml) -> Self { - Self { - num_skipped_slots: as_usize(yaml, "num_skipped_slots"), - state_checks: parse_state_checks(yaml), - } - } -} - -/// Parse the `state_checks` section of the YAML document. -fn parse_state_checks(yaml: &Yaml) -> Option> { - let mut states = vec![]; - - for state_yaml in yaml["states"].as_vec()? { - states.push(StateCheck::from_yaml(state_yaml)); - } - - Some(states) -} diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs b/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs deleted file mode 100644 index c6bdf8978..000000000 --- a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::yaml_helpers::{as_u64, as_usize, as_vec_u64}; -use log::info; -use types::*; -use yaml_rust::Yaml; - -type ValidatorIndex = u64; -type BalanceGwei = u64; - -type BalanceCheckTuple = (ValidatorIndex, String, BalanceGwei); - -/// Tests to be conducted upon a `BeaconState` object generated during the execution of a -/// `TestCase`. -#[derive(Debug)] -pub struct StateCheck { - /// Checked against `beacon_state.slot`. - pub slot: Slot, - /// Checked against `beacon_state.validator_registry.len()`. - pub num_validators: Option, - /// The number of pending attestations from the previous epoch that should be in the state. - pub num_previous_epoch_attestations: Option, - /// The number of pending attestations from the current epoch that should be in the state. - pub num_current_epoch_attestations: Option, - /// A list of validator indices which have been penalized. Must be in ascending order. - pub slashed_validators: Option>, - /// A list of validator indices which have been fully exited. Must be in ascending order. - pub exited_validators: Option>, - /// A list of validator indices which have had an exit initiated. Must be in ascending order. - pub exit_initiated_validators: Option>, - /// A list of balances to check. - pub balances: Option>, -} - -impl StateCheck { - /// Load from a YAML document. - /// - /// Expects the `state_check` section of the YAML document. - pub fn from_yaml(yaml: &Yaml) -> Self { - Self { - slot: Slot::from(as_u64(&yaml, "slot").expect("State must specify slot")), - num_validators: as_usize(&yaml, "num_validators"), - num_previous_epoch_attestations: as_usize(&yaml, "num_previous_epoch_attestations"), - num_current_epoch_attestations: as_usize(&yaml, "num_current_epoch_attestations"), - slashed_validators: as_vec_u64(&yaml, "slashed_validators"), - exited_validators: as_vec_u64(&yaml, "exited_validators"), - exit_initiated_validators: as_vec_u64(&yaml, "exit_initiated_validators"), - balances: parse_balances(&yaml), - } - } - - /// Performs all checks against a `BeaconState` - /// - /// # Panics - /// - /// Panics with an error message if any test fails. - #[allow(clippy::cyclomatic_complexity)] - pub fn assert_valid(&self, state: &BeaconState, spec: &ChainSpec) { - let state_epoch = state.slot.epoch(spec.slots_per_epoch); - - info!("Running state check for slot height {}.", self.slot); - - // Check the state slot. - assert_eq!( - self.slot, - state.slot - spec.genesis_epoch.start_slot(spec.slots_per_epoch), - "State slot is invalid." - ); - - // Check the validator count - if let Some(num_validators) = self.num_validators { - assert_eq!( - state.validator_registry.len(), - num_validators, - "State validator count != expected." - ); - info!("OK: num_validators = {}.", num_validators); - } - - // Check the previous epoch attestations - if let Some(n) = self.num_previous_epoch_attestations { - assert_eq!( - state.previous_epoch_attestations.len(), - n, - "previous epoch attestations count != expected." - ); - info!("OK: num_previous_epoch_attestations = {}.", n); - } - - // Check the current epoch attestations - if let Some(n) = self.num_current_epoch_attestations { - assert_eq!( - state.current_epoch_attestations.len(), - n, - "current epoch attestations count != expected." - ); - info!("OK: num_current_epoch_attestations = {}.", n); - } - - // Check for slashed validators. - if let Some(ref slashed_validators) = self.slashed_validators { - let actually_slashed_validators: Vec = state - .validator_registry - .iter() - .enumerate() - .filter_map(|(i, validator)| { - if validator.slashed { - Some(i as u64) - } else { - None - } - }) - .collect(); - assert_eq!( - actually_slashed_validators, *slashed_validators, - "Slashed validators != expected." - ); - info!("OK: slashed_validators = {:?}.", slashed_validators); - } - - // Check for exited validators. - if let Some(ref exited_validators) = self.exited_validators { - let actually_exited_validators: Vec = state - .validator_registry - .iter() - .enumerate() - .filter_map(|(i, validator)| { - if validator.is_exited_at(state_epoch) { - Some(i as u64) - } else { - None - } - }) - .collect(); - assert_eq!( - actually_exited_validators, *exited_validators, - "Exited validators != expected." - ); - info!("OK: exited_validators = {:?}.", exited_validators); - } - - // Check for validators that have initiated exit. - if let Some(ref exit_initiated_validators) = self.exit_initiated_validators { - let actual: Vec = state - .validator_registry - .iter() - .enumerate() - .filter_map(|(i, validator)| { - if validator.initiated_exit { - Some(i as u64) - } else { - None - } - }) - .collect(); - assert_eq!( - actual, *exit_initiated_validators, - "Exit initiated validators != expected." - ); - info!( - "OK: exit_initiated_validators = {:?}.", - exit_initiated_validators - ); - } - - // Check validator balances. - if let Some(ref balances) = self.balances { - for (index, comparison, expected) in balances { - let actual = *state - .validator_balances - .get(*index as usize) - .expect("Balance check specifies unknown validator"); - - let result = match comparison.as_ref() { - "eq" => actual == *expected, - _ => panic!("Unknown balance comparison (use `eq`)"), - }; - assert!( - result, - format!( - "Validator balance for {}: {} !{} {}.", - index, actual, comparison, expected - ) - ); - info!("OK: validator balance for {:?}.", index); - } - } - } -} - -/// Parse the `transfers` section of the YAML document. -fn parse_balances(yaml: &Yaml) -> Option> { - let mut tuples = vec![]; - - for exit in yaml["balances"].as_vec()? { - let from = - as_u64(exit, "validator_index").expect("Incomplete balance check (validator_index)"); - let comparison = exit["comparison"] - .clone() - .into_string() - .expect("Incomplete balance check (amount)"); - let balance = as_u64(exit, "balance").expect("Incomplete balance check (balance)"); - - tuples.push((from, comparison, balance)); - } - - Some(tuples) -} diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/yaml_helpers.rs b/beacon_node/beacon_chain/test_harness/src/test_case/yaml_helpers.rs deleted file mode 100644 index c499b3c0f..000000000 --- a/beacon_node/beacon_chain/test_harness/src/test_case/yaml_helpers.rs +++ /dev/null @@ -1,19 +0,0 @@ -use yaml_rust::Yaml; - -pub fn as_usize(yaml: &Yaml, key: &str) -> Option { - yaml[key].as_i64().and_then(|n| Some(n as usize)) -} - -pub fn as_u64(yaml: &Yaml, key: &str) -> Option { - yaml[key].as_i64().and_then(|n| Some(n as u64)) -} - -pub fn as_vec_u64(yaml: &Yaml, key: &str) -> Option> { - yaml[key].clone().into_vec().and_then(|vec| { - Some( - vec.iter() - .map(|item| item.as_i64().unwrap() as u64) - .collect(), - ) - }) -} diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs deleted file mode 100644 index d47fd44b9..000000000 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs +++ /dev/null @@ -1,100 +0,0 @@ -use attester::{ - BeaconNode as AttesterBeaconNode, BeaconNodeError as NodeError, - PublishOutcome as AttestationPublishOutcome, -}; -use beacon_chain::BeaconChain; -use block_proposer::{ - BeaconNode as BeaconBlockNode, BeaconNodeError as BeaconBlockNodeError, - PublishOutcome as BlockPublishOutcome, -}; -use db::ClientDB; -use fork_choice::ForkChoice; -use parking_lot::RwLock; -use slot_clock::SlotClock; -use std::sync::Arc; -use types::{AttestationData, BeaconBlock, FreeAttestation, Signature, Slot}; - -/// Connect directly to a borrowed `BeaconChain` instance so an attester/producer can request/submit -/// blocks/attestations. -/// -/// `BeaconBlock`s and `FreeAttestation`s are not actually published to the `BeaconChain`, instead -/// they are stored inside this struct. This is to allow one to benchmark the submission of the -/// block/attestation directly, or modify it before submission. -pub struct DirectBeaconNode { - beacon_chain: Arc>, - published_blocks: RwLock>, - published_attestations: RwLock>, -} - -impl DirectBeaconNode { - pub fn new(beacon_chain: Arc>) -> Self { - Self { - beacon_chain, - published_blocks: RwLock::new(vec![]), - published_attestations: RwLock::new(vec![]), - } - } - - /// Get the last published block (if any). - pub fn last_published_block(&self) -> Option { - Some(self.published_blocks.read().last()?.clone()) - } -} - -impl AttesterBeaconNode for DirectBeaconNode { - fn produce_attestation_data( - &self, - _slot: Slot, - shard: u64, - ) -> Result, NodeError> { - match self.beacon_chain.produce_attestation_data(shard) { - Ok(attestation_data) => Ok(Some(attestation_data)), - Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))), - } - } - - fn publish_attestation( - &self, - free_attestation: FreeAttestation, - ) -> Result { - self.published_attestations.write().push(free_attestation); - Ok(AttestationPublishOutcome::ValidAttestation) - } -} - -impl BeaconBlockNode for DirectBeaconNode { - /// Requests a new `BeaconBlock from the `BeaconChain`. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result, BeaconBlockNodeError> { - let (block, _state) = self - .beacon_chain - .produce_block(randao_reveal.clone()) - .map_err(|e| { - BeaconBlockNodeError::RemoteFailure(format!("Did not produce block: {:?}", e)) - })?; - - if block.slot == slot { - Ok(Some(block)) - } else { - Err(BeaconBlockNodeError::RemoteFailure( - "Unable to produce at non-current slot.".to_string(), - )) - } - } - - /// A block is not _actually_ published to the `BeaconChain`, instead it is stored in the - /// `published_block_vec` and a successful `ValidBlock` is returned to the caller. - /// - /// The block may be retrieved and then applied to the `BeaconChain` manually, potentially in a - /// benchmarking scenario. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result { - self.published_blocks.write().push(block); - Ok(BlockPublishOutcome::ValidBlock) - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_duties.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_duties.rs deleted file mode 100644 index dec93c334..000000000 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_duties.rs +++ /dev/null @@ -1,74 +0,0 @@ -use attester::{ - DutiesReader as AttesterDutiesReader, DutiesReaderError as AttesterDutiesReaderError, -}; -use beacon_chain::BeaconChain; -use block_proposer::{ - DutiesReader as ProducerDutiesReader, DutiesReaderError as ProducerDutiesReaderError, -}; -use db::ClientDB; -use fork_choice::ForkChoice; -use slot_clock::SlotClock; -use std::sync::Arc; -use types::{Fork, PublicKey, Slot}; - -/// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from -/// it. -pub struct DirectDuties { - beacon_chain: Arc>, - pubkey: PublicKey, -} - -impl DirectDuties { - pub fn new(pubkey: PublicKey, beacon_chain: Arc>) -> Self { - Self { - beacon_chain, - pubkey, - } - } -} - -impl ProducerDutiesReader for DirectDuties { - fn is_block_production_slot(&self, slot: Slot) -> Result { - let validator_index = self - .beacon_chain - .validator_index(&self.pubkey) - .ok_or_else(|| ProducerDutiesReaderError::UnknownValidator)?; - - match self.beacon_chain.block_proposer(slot) { - Ok(proposer) if proposer == validator_index => Ok(true), - Ok(_) => Ok(false), - Err(_) => Err(ProducerDutiesReaderError::UnknownEpoch), - } - } - - fn fork(&self) -> Result { - Ok(self.beacon_chain.state.read().fork.clone()) - } -} - -impl AttesterDutiesReader for DirectDuties { - fn validator_index(&self) -> Option { - match self.beacon_chain.validator_index(&self.pubkey) { - Some(index) => Some(index as u64), - None => None, - } - } - - fn attestation_shard(&self, slot: Slot) -> Result, AttesterDutiesReaderError> { - if let Some(validator_index) = self.validator_index() { - match self - .beacon_chain - .validator_attestion_slot_and_shard(validator_index as usize) - { - Ok(Some((attest_slot, attest_shard))) if attest_slot == slot => { - Ok(Some(attest_shard)) - } - Ok(Some(_)) => Ok(None), - Ok(None) => Err(AttesterDutiesReaderError::UnknownEpoch), - Err(_) => unreachable!("Error when getting validator attestation shard."), - } - } else { - Err(AttesterDutiesReaderError::UnknownValidator) - } - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/local_signer.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/local_signer.rs deleted file mode 100644 index 803af5045..000000000 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/local_signer.rs +++ /dev/null @@ -1,36 +0,0 @@ -use attester::Signer as AttesterSigner; -use block_proposer::Signer as BlockProposerSigner; -use types::{Keypair, Signature}; - -/// A test-only struct used to perform signing for a proposer or attester. -pub struct LocalSigner { - keypair: Keypair, -} - -impl LocalSigner { - /// Produce a new TestSigner with signing enabled by default. - pub fn new(keypair: Keypair) -> Self { - Self { keypair } - } - - /// Sign some message. - fn bls_sign(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.keypair.sk)) - } -} - -impl BlockProposerSigner for LocalSigner { - fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option { - self.bls_sign(message, domain) - } - - fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option { - self.bls_sign(message, domain) - } -} - -impl AttesterSigner for LocalSigner { - fn sign_attestation_message(&self, message: &[u8], domain: u64) -> Option { - self.bls_sign(message, domain) - } -} diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs deleted file mode 100644 index 815d4b23b..000000000 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs +++ /dev/null @@ -1,119 +0,0 @@ -mod direct_beacon_node; -mod direct_duties; -mod local_signer; - -use attester::Attester; -use beacon_chain::BeaconChain; -use block_proposer::PollOutcome as BlockPollOutcome; -use block_proposer::{BlockProducer, Error as BlockPollError}; -use db::MemoryDB; -use direct_beacon_node::DirectBeaconNode; -use direct_duties::DirectDuties; -use fork_choice::BitwiseLMDGhost; -use local_signer::LocalSigner; -use slot_clock::TestingSlotClock; -use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Keypair, Slot}; - -#[derive(Debug, PartialEq)] -pub enum BlockProduceError { - DidNotProduce(BlockPollOutcome), - PollError(BlockPollError), -} - -type TestingBlockProducer = BlockProducer< - TestingSlotClock, - DirectBeaconNode>, - DirectDuties>, - LocalSigner, ->; - -type TestingAttester = Attester< - TestingSlotClock, - DirectBeaconNode>, - DirectDuties>, - LocalSigner, ->; - -/// A `BlockProducer` and `Attester` which sign using a common keypair. -/// -/// The test validator connects directly to a borrowed `BeaconChain` struct. It is useful for -/// testing that the core proposer and attester logic is functioning. Also for supporting beacon -/// chain tests. -pub struct ValidatorHarness { - pub block_producer: TestingBlockProducer, - pub attester: TestingAttester, - pub spec: Arc, - pub epoch_map: Arc>>, - pub keypair: Keypair, - pub beacon_node: Arc>>, - pub slot_clock: Arc, - pub signer: Arc, -} - -impl ValidatorHarness { - /// Create a new ValidatorHarness that signs with the given keypair, operates per the given spec and connects to the - /// supplied beacon node. - /// - /// A `BlockProducer` and `Attester` is created.. - pub fn new( - keypair: Keypair, - beacon_chain: Arc>>, - spec: Arc, - ) -> Self { - let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot.as_u64())); - let signer = Arc::new(LocalSigner::new(keypair.clone())); - let beacon_node = Arc::new(DirectBeaconNode::new(beacon_chain.clone())); - let epoch_map = Arc::new(DirectDuties::new(keypair.pk.clone(), beacon_chain.clone())); - - let block_producer = BlockProducer::new( - spec.clone(), - epoch_map.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - let attester = Attester::new( - epoch_map.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - Self { - block_producer, - attester, - spec, - epoch_map, - keypair, - beacon_node, - slot_clock, - signer, - } - } - - /// Run the `poll` function on the `BlockProducer` and produce a block. - /// - /// An error is returned if the producer refuses to produce. - pub fn produce_block(&mut self) -> Result { - // Using `DirectBeaconNode`, the validator will always return sucessufully if it tries to - // publish a block. - match self.block_producer.poll() { - Ok(BlockPollOutcome::BlockProduced(_)) => {} - Ok(outcome) => return Err(BlockProduceError::DidNotProduce(outcome)), - Err(error) => return Err(BlockProduceError::PollError(error)), - }; - Ok(self - .beacon_node - .last_published_block() - .expect("Unable to obtain produced block.")) - } - - /// Set the validators slot clock to the specified slot. - /// - /// The validators slot clock will always read this value until it is set to something else. - pub fn set_slot(&mut self, slot: Slot) { - self.slot_clock.set_slot(slot.as_u64()) - } -} diff --git a/beacon_node/beacon_chain/test_harness/tests/chain.rs b/beacon_node/beacon_chain/test_harness/tests/chain.rs deleted file mode 100644 index d47de6889..000000000 --- a/beacon_node/beacon_chain/test_harness/tests/chain.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![cfg(not(debug_assertions))] - -use env_logger::{Builder, Env}; -use log::debug; -use test_harness::BeaconChainHarness; -use types::ChainSpec; - -#[test] -fn it_can_build_on_genesis_block() { - Builder::from_env(Env::default().default_filter_or("info")).init(); - - let spec = ChainSpec::few_validators(); - let validator_count = 8; - - let mut harness = BeaconChainHarness::new(spec, validator_count as usize); - - harness.advance_chain_with_block(); -} - -#[test] -#[ignore] -fn it_can_produce_past_first_epoch_boundary() { - Builder::from_env(Env::default().default_filter_or("info")).init(); - - let spec = ChainSpec::few_validators(); - let validator_count = 8; - - debug!("Starting harness build..."); - - let mut harness = BeaconChainHarness::new(spec, validator_count); - - debug!("Harness built, tests starting.."); - - let blocks = harness.spec.slots_per_epoch * 2 + 1; - - for i in 0..blocks { - harness.advance_chain_with_block(); - debug!("Produced block {}/{}.", i + 1, blocks); - } - - harness.run_fork_choice(); - - let dump = harness.chain_dump().expect("Chain dump failed."); - - assert_eq!(dump.len() as u64, blocks + 1); // + 1 for genesis block. -} diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 407171ff5..d84b63f4f 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -9,8 +9,8 @@ use std::net::{IpAddr, Ipv4Addr}; use std::path::PathBuf; use types::multiaddr::Protocol; use types::multiaddr::ToMultiaddr; -use types::ChainSpec; use types::Multiaddr; +use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec}; /// Stores the client configuration for this Lighthouse instance. #[derive(Debug, Clone)] @@ -35,7 +35,7 @@ impl Default for ClientConfig { fs::create_dir_all(&data_dir) .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir)); - let default_spec = ChainSpec::lighthouse_testnet(); + let default_spec = LighthouseTestnetEthSpec::spec(); let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone()); Self { diff --git a/beacon_node/client/src/client_types.rs b/beacon_node/client/src/client_types.rs index f5abc77ce..8c9352d7c 100644 --- a/beacon_node/client/src/client_types.rs +++ b/beacon_node/client/src/client_types.rs @@ -1,23 +1,22 @@ -use crate::ClientConfig; +use crate::{ArcBeaconChain, ClientConfig}; use beacon_chain::{ db::{ClientDB, DiskDB, MemoryDB}, fork_choice::BitwiseLMDGhost, initialise, slot_clock::{SlotClock, SystemTimeSlotClock}, - BeaconChain, }; use fork_choice::ForkChoice; - -use std::sync::Arc; +use types::{EthSpec, FewValidatorsEthSpec, FoundationEthSpec}; pub trait ClientTypes { type DB: ClientDB + 'static; type SlotClock: SlotClock + 'static; type ForkChoice: ForkChoice + 'static; + type EthSpec: EthSpec + 'static; fn initialise_beacon_chain( config: &ClientConfig, - ) -> Arc>; + ) -> ArcBeaconChain; } pub struct StandardClientType; @@ -25,11 +24,12 @@ pub struct StandardClientType; impl ClientTypes for StandardClientType { type DB = DiskDB; type SlotClock = SystemTimeSlotClock; - type ForkChoice = BitwiseLMDGhost; + type ForkChoice = BitwiseLMDGhost; + type EthSpec = FoundationEthSpec; fn initialise_beacon_chain( config: &ClientConfig, - ) -> Arc> { + ) -> ArcBeaconChain { initialise::initialise_beacon_chain(&config.spec, Some(&config.db_name)) } } @@ -39,11 +39,12 @@ pub struct TestingClientType; impl ClientTypes for TestingClientType { type DB = MemoryDB; type SlotClock = SystemTimeSlotClock; - type ForkChoice = BitwiseLMDGhost; + type ForkChoice = BitwiseLMDGhost; + type EthSpec = FewValidatorsEthSpec; fn initialise_beacon_chain( config: &ClientConfig, - ) -> Arc> { + ) -> ArcBeaconChain { initialise::initialise_test_beacon_chain(&config.spec, None) } } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 6a21493b1..5d7c221ef 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -20,6 +20,9 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; use tokio::timer::Interval; +use types::EthSpec; + +type ArcBeaconChain = Arc>; /// Main beacon node client service. This provides the connection and initialisation of the clients /// sub-services in multiple threads. @@ -27,9 +30,9 @@ pub struct Client { /// Configuration for the lighthouse client. _config: ClientConfig, /// The beacon chain for the running client. - _beacon_chain: Arc>, + _beacon_chain: ArcBeaconChain, /// Reference to the network service. - pub network: Arc, + pub network: Arc>, /// Signal to terminate the RPC server. pub rpc_exit_signal: Option, /// Signal to terminate the slot timer. @@ -141,11 +144,12 @@ impl Client { } } -fn do_state_catchup(chain: &Arc>, log: &slog::Logger) +fn do_state_catchup(chain: &Arc>, log: &slog::Logger) where T: ClientDB, U: SlotClock, F: ForkChoice, + E: EthSpec, { if let Some(genesis_height) = chain.slots_since_genesis() { let result = chain.catchup_state(); diff --git a/beacon_node/db/src/disk_db.rs b/beacon_node/db/src/disk_db.rs index 9d8a71bc4..2d26315da 100644 --- a/beacon_node/db/src/disk_db.rs +++ b/beacon_node/db/src/disk_db.rs @@ -97,7 +97,7 @@ impl ClientDB for DiskDB { None => Err(DBError { message: "Unknown column".to_string(), }), - Some(handle) => self.db.put_cf(handle, key, val).map_err(|e| e.into()), + Some(handle) => self.db.put_cf(handle, key, val).map_err(Into::into), } } diff --git a/beacon_node/db/src/stores/beacon_block_store.rs b/beacon_node/db/src/stores/beacon_block_store.rs index 45c7ac8de..868caafe2 100644 --- a/beacon_node/db/src/stores/beacon_block_store.rs +++ b/beacon_node/db/src/stores/beacon_block_store.rs @@ -1,6 +1,6 @@ use super::BLOCKS_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; -use ssz::decode; +use ssz::Decode; use std::sync::Arc; use types::{BeaconBlock, Hash256, Slot}; @@ -30,7 +30,7 @@ impl BeaconBlockStore { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let block = decode::(&ssz).map_err(|_| DBError { + let block = BeaconBlock::from_ssz_bytes(&ssz).map_err(|_| DBError { message: "Bad BeaconBlock SSZ.".to_string(), })?; Ok(Some(block)) diff --git a/beacon_node/db/src/stores/beacon_state_store.rs b/beacon_node/db/src/stores/beacon_state_store.rs index bb046a113..044290592 100644 --- a/beacon_node/db/src/stores/beacon_state_store.rs +++ b/beacon_node/db/src/stores/beacon_state_store.rs @@ -1,8 +1,8 @@ use super::STATES_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; -use ssz::decode; +use ssz::Decode; use std::sync::Arc; -use types::{BeaconState, Hash256}; +use types::{BeaconState, EthSpec, Hash256}; pub struct BeaconStateStore where @@ -19,11 +19,14 @@ impl BeaconStateStore { Self { db } } - pub fn get_deserialized(&self, hash: &Hash256) -> Result, DBError> { + pub fn get_deserialized( + &self, + hash: &Hash256, + ) -> Result>, DBError> { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let state = decode::(&ssz).map_err(|_| DBError { + let state = BeaconState::from_ssz_bytes(&ssz).map_err(|_| DBError { message: "Bad State SSZ.".to_string(), })?; Ok(Some(state)) @@ -40,7 +43,7 @@ mod tests { use ssz::ssz_encode; use std::sync::Arc; use types::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use types::Hash256; + use types::{FoundationBeaconState, Hash256}; test_crud_for_store!(BeaconStateStore, DB_COLUMN); @@ -50,7 +53,7 @@ mod tests { let store = BeaconStateStore::new(db.clone()); let mut rng = XorShiftRng::from_seed([42; 16]); - let state = BeaconState::random_for_test(&mut rng); + let state: FoundationBeaconState = BeaconState::random_for_test(&mut rng); let state_root = state.canonical_root(); store.put(&state_root, &ssz_encode(&state)).unwrap(); diff --git a/beacon_node/db/src/stores/validator_store.rs b/beacon_node/db/src/stores/validator_store.rs index 7d9c24546..f653c9f71 100644 --- a/beacon_node/db/src/stores/validator_store.rs +++ b/beacon_node/db/src/stores/validator_store.rs @@ -4,7 +4,7 @@ use self::bytes::{BufMut, BytesMut}; use super::VALIDATOR_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; use bls::PublicKey; -use ssz::{decode, ssz_encode}; +use ssz::{Decode, Encode}; use std::sync::Arc; #[derive(Debug, PartialEq)] @@ -55,7 +55,7 @@ impl ValidatorStore { public_key: &PublicKey, ) -> Result<(), ValidatorStoreError> { let key = self.get_db_key_for_index(&KeyPrefixes::PublicKey, index); - let val = ssz_encode(public_key); + let val = public_key.as_ssz_bytes(); self.db .put(DB_COLUMN, &key[..], &val[..]) .map_err(ValidatorStoreError::from) @@ -69,7 +69,7 @@ impl ValidatorStore { let val = self.db.get(DB_COLUMN, &key[..])?; match val { None => Ok(None), - Some(val) => match decode::(&val) { + Some(val) => match PublicKey::from_ssz_bytes(&val) { Ok(key) => Ok(Some(key)), Err(_) => Err(ValidatorStoreError::DecodeError), }, @@ -125,7 +125,7 @@ mod tests { .unwrap() .unwrap(); - assert_eq!(public_key_at_index, ssz_encode(&public_key)); + assert_eq!(public_key_at_index, public_key.as_ssz_bytes()); } #[test] @@ -139,7 +139,7 @@ mod tests { db.put( DB_COLUMN, &store.get_db_key_for_index(&KeyPrefixes::PublicKey, index)[..], - &ssz_encode(&public_key)[..], + &public_key.as_ssz_bytes(), ) .unwrap(); @@ -157,7 +157,7 @@ mod tests { db.put( DB_COLUMN, &store.get_db_key_for_index(&KeyPrefixes::PublicKey, 3)[..], - &ssz_encode(&public_key)[..], + &public_key.as_ssz_bytes(), ) .unwrap(); diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index e1112e6ff..8f3a000e1 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -13,7 +13,7 @@ use libp2p::{ NetworkBehaviour, PeerId, }; use slog::{debug, o, trace, warn}; -use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{ssz_encode, Decode, DecodeError, Encode}; use types::{Attestation, BeaconBlock}; use types::{Topic, TopicHash}; @@ -49,7 +49,7 @@ impl NetworkBehaviourEventProcess { trace!(self.log, "Received GossipEvent"; "msg" => format!("{:?}", gs_msg)); - let pubsub_message = match PubsubMessage::ssz_decode(&gs_msg.data, 0) { + let pubsub_message = match PubsubMessage::from_ssz_bytes(&gs_msg.data) { //TODO: Punish peer on error Err(e) => { warn!( @@ -59,7 +59,7 @@ impl NetworkBehaviourEventProcess msg, + Ok(msg) => msg, }; self.events.push(BehaviourEvent::GossipMessage { @@ -197,34 +197,59 @@ pub enum PubsubMessage { } //TODO: Correctly encode/decode enums. Prefixing with integer for now. -impl Encodable for PubsubMessage { - fn ssz_append(&self, s: &mut SszStream) { +impl Encode for PubsubMessage { + fn is_ssz_fixed_len() -> bool { + false + } + + fn ssz_append(&self, buf: &mut Vec) { + let offset = ::ssz_fixed_len() + as Encode>::ssz_fixed_len(); + + let mut encoder = ssz::SszEncoder::container(buf, offset); + match self { PubsubMessage::Block(block_gossip) => { - 0u32.ssz_append(s); - block_gossip.ssz_append(s); + encoder.append(&0_u32); + + // Encode the gossip as a Vec; + encoder.append(&block_gossip.as_ssz_bytes()); } PubsubMessage::Attestation(attestation_gossip) => { - 1u32.ssz_append(s); - attestation_gossip.ssz_append(s); + encoder.append(&1_u32); + + // Encode the gossip as a Vec; + encoder.append(&attestation_gossip.as_ssz_bytes()); } } + + encoder.finalize(); } } -impl Decodable for PubsubMessage { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - let (id, index) = u32::ssz_decode(bytes, index)?; +impl Decode for PubsubMessage { + fn is_ssz_fixed_len() -> bool { + false + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let mut builder = ssz::SszDecoderBuilder::new(&bytes); + + builder.register_type::()?; + builder.register_type::>()?; + + let mut decoder = builder.build()?; + + let id: u32 = decoder.decode_next()?; + let body: Vec = decoder.decode_next()?; + match id { - 0 => { - let (block, index) = BeaconBlock::ssz_decode(bytes, index)?; - Ok((PubsubMessage::Block(block), index)) - } - 1 => { - let (attestation, index) = Attestation::ssz_decode(bytes, index)?; - Ok((PubsubMessage::Attestation(attestation), index)) - } - _ => Err(DecodeError::Invalid), + 0 => Ok(PubsubMessage::Block(BeaconBlock::from_ssz_bytes(&body)?)), + 1 => Ok(PubsubMessage::Attestation(Attestation::from_ssz_bytes( + &body, + )?)), + _ => Err(DecodeError::BytesInvalid( + "Invalid PubsubMessage id".to_string(), + )), } } } @@ -236,13 +261,11 @@ mod test { #[test] fn ssz_encoding() { - let original = PubsubMessage::Block(BeaconBlock::empty(&ChainSpec::foundation())); + let original = PubsubMessage::Block(BeaconBlock::empty(&FoundationEthSpec::spec())); let encoded = ssz_encode(&original); - println!("{:?}", encoded); - - let (decoded, _i) = PubsubMessage::ssz_decode(&encoded, 0).unwrap(); + let decoded = PubsubMessage::from_ssz_bytes(&encoded).unwrap(); assert_eq!(original, decoded); } diff --git a/beacon_node/eth2-libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs index dc0be19a9..ef7315765 100644 --- a/beacon_node/eth2-libp2p/src/rpc/methods.rs +++ b/beacon_node/eth2-libp2p/src/rpc/methods.rs @@ -1,5 +1,6 @@ -use ssz::{Decodable, DecodeError, Encodable, SszStream}; -/// Available RPC methods types and ids. +//!Available RPC methods types and ids. + +use ssz::{impl_decode_via_from, impl_encode_via_from}; use ssz_derive::{Decode, Encode}; use types::{BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; @@ -149,19 +150,8 @@ impl Into for GoodbyeReason { } } -impl Encodable for GoodbyeReason { - fn ssz_append(&self, s: &mut SszStream) { - let id: u64 = (*self).clone().into(); - id.ssz_append(s); - } -} - -impl Decodable for GoodbyeReason { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - let (id, index) = u64::ssz_decode(bytes, index)?; - Ok((Self::from(id), index)) - } -} +impl_encode_via_from!(GoodbyeReason, u64); +impl_decode_via_from!(GoodbyeReason, u64); /// Request a number of beacon block roots from a peer. #[derive(Encode, Decode, Clone, Debug, PartialEq)] diff --git a/beacon_node/eth2-libp2p/src/rpc/protocol.rs b/beacon_node/eth2-libp2p/src/rpc/protocol.rs index 5c1c47fbf..82257cc32 100644 --- a/beacon_node/eth2-libp2p/src/rpc/protocol.rs +++ b/beacon_node/eth2-libp2p/src/rpc/protocol.rs @@ -1,6 +1,6 @@ use super::methods::*; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; -use ssz::{ssz_encode, Decodable, DecodeError as SSZDecodeError, Encodable, SszStream}; +use ssz::{impl_decode_via_from, impl_encode_via_from, ssz_encode, Decode, Encode}; use std::hash::{Hash, Hasher}; use std::io; use std::iter; @@ -72,18 +72,8 @@ impl Into for RequestId { } } -impl Encodable for RequestId { - fn ssz_append(&self, s: &mut SszStream) { - self.0.ssz_append(s); - } -} - -impl Decodable for RequestId { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), SSZDecodeError> { - let (id, index) = u64::ssz_decode(bytes, index)?; - Ok((Self::from(id), index)) - } -} +impl_encode_via_from!(RequestId, u64); +impl_decode_via_from!(RequestId, u64); /// The RPC types which are sent/received in this protocol. #[derive(Debug, Clone)] @@ -125,42 +115,40 @@ where } } +// NOTE! +// +// This code has not been tested, it is a placeholder until we can update to the new libp2p +// spec. fn decode(packet: Vec) -> Result { - // decode the header of the rpc - // request/response - let (request, index) = bool::ssz_decode(&packet, 0)?; - let (id, index) = RequestId::ssz_decode(&packet, index)?; - let (method_id, index) = u16::ssz_decode(&packet, index)?; + let mut builder = ssz::SszDecoderBuilder::new(&packet); + + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::>()?; + + let mut decoder = builder.build()?; + + let request: bool = decoder.decode_next()?; + let id: RequestId = decoder.decode_next()?; + let method_id: u16 = decoder.decode_next()?; + let bytes: Vec = decoder.decode_next()?; if request { let body = match RPCMethod::from(method_id) { - RPCMethod::Hello => { - let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?; - RPCRequest::Hello(hello_body) - } - RPCMethod::Goodbye => { - let (goodbye_reason, _index) = GoodbyeReason::ssz_decode(&packet, index)?; - RPCRequest::Goodbye(goodbye_reason) - } + RPCMethod::Hello => RPCRequest::Hello(HelloMessage::from_ssz_bytes(&bytes)?), + RPCMethod::Goodbye => RPCRequest::Goodbye(GoodbyeReason::from_ssz_bytes(&bytes)?), RPCMethod::BeaconBlockRoots => { - let (block_roots_request, _index) = - BeaconBlockRootsRequest::ssz_decode(&packet, index)?; - RPCRequest::BeaconBlockRoots(block_roots_request) + RPCRequest::BeaconBlockRoots(BeaconBlockRootsRequest::from_ssz_bytes(&bytes)?) } RPCMethod::BeaconBlockHeaders => { - let (block_headers_request, _index) = - BeaconBlockHeadersRequest::ssz_decode(&packet, index)?; - RPCRequest::BeaconBlockHeaders(block_headers_request) + RPCRequest::BeaconBlockHeaders(BeaconBlockHeadersRequest::from_ssz_bytes(&bytes)?) } RPCMethod::BeaconBlockBodies => { - let (block_bodies_request, _index) = - BeaconBlockBodiesRequest::ssz_decode(&packet, index)?; - RPCRequest::BeaconBlockBodies(block_bodies_request) + RPCRequest::BeaconBlockBodies(BeaconBlockBodiesRequest::from_ssz_bytes(&bytes)?) } RPCMethod::BeaconChainState => { - let (chain_state_request, _index) = - BeaconChainStateRequest::ssz_decode(&packet, index)?; - RPCRequest::BeaconChainState(chain_state_request) + RPCRequest::BeaconChainState(BeaconChainStateRequest::from_ssz_bytes(&bytes)?) } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; @@ -174,29 +162,24 @@ fn decode(packet: Vec) -> Result { // we have received a response else { let result = match RPCMethod::from(method_id) { - RPCMethod::Hello => { - let (body, _index) = HelloMessage::ssz_decode(&packet, index)?; - RPCResponse::Hello(body) - } - RPCMethod::Goodbye => unreachable!("Should never receive a goodbye response"), + RPCMethod::Hello => RPCResponse::Hello(HelloMessage::from_ssz_bytes(&bytes)?), RPCMethod::BeaconBlockRoots => { - let (body, _index) = BeaconBlockRootsResponse::ssz_decode(&packet, index)?; - RPCResponse::BeaconBlockRoots(body) + RPCResponse::BeaconBlockRoots(BeaconBlockRootsResponse::from_ssz_bytes(&bytes)?) } RPCMethod::BeaconBlockHeaders => { - let (body, _index) = BeaconBlockHeadersResponse::ssz_decode(&packet, index)?; - RPCResponse::BeaconBlockHeaders(body) + RPCResponse::BeaconBlockHeaders(BeaconBlockHeadersResponse::from_ssz_bytes(&bytes)?) } RPCMethod::BeaconBlockBodies => { - let (body, _index) = BeaconBlockBodiesResponse::ssz_decode(&packet, index)?; - RPCResponse::BeaconBlockBodies(body) + RPCResponse::BeaconBlockBodies(BeaconBlockBodiesResponse::from_ssz_bytes(&packet)?) } RPCMethod::BeaconChainState => { - let (body, _index) = BeaconChainStateResponse::ssz_decode(&packet, index)?; - RPCResponse::BeaconChainState(body) + RPCResponse::BeaconChainState(BeaconChainStateResponse::from_ssz_bytes(&packet)?) } + // We should never receive a goodbye response; it is invalid. + RPCMethod::Goodbye => return Err(DecodeError::UnknownRPCMethod), RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; + Ok(RPCEvent::Response { id, method_id, @@ -220,35 +203,51 @@ where } } -impl Encodable for RPCEvent { - fn ssz_append(&self, s: &mut SszStream) { +impl Encode for RPCEvent { + fn is_ssz_fixed_len() -> bool { + false + } + + // NOTE! + // + // This code has not been tested, it is a placeholder until we can update to the new libp2p + // spec. + fn ssz_append(&self, buf: &mut Vec) { + let offset = ::ssz_fixed_len() + + ::ssz_fixed_len() + + as Encode>::ssz_fixed_len(); + + let mut encoder = ssz::SszEncoder::container(buf, offset); + match self { RPCEvent::Request { id, method_id, body, } => { - s.append(&true); - s.append(id); - s.append(method_id); + encoder.append(&true); + encoder.append(id); + encoder.append(method_id); + + // Encode the `body` as a `Vec`. match body { RPCRequest::Hello(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } RPCRequest::Goodbye(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } RPCRequest::BeaconBlockRoots(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } RPCRequest::BeaconBlockHeaders(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } RPCRequest::BeaconBlockBodies(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } RPCRequest::BeaconChainState(body) => { - s.append(body); + encoder.append(&body.as_ssz_bytes()); } } } @@ -257,28 +256,32 @@ impl Encodable for RPCEvent { method_id, result, } => { - s.append(&false); - s.append(id); - s.append(method_id); + encoder.append(&true); + encoder.append(id); + encoder.append(method_id); + match result { RPCResponse::Hello(response) => { - s.append(response); + encoder.append(&response.as_ssz_bytes()); } RPCResponse::BeaconBlockRoots(response) => { - s.append(response); + encoder.append(&response.as_ssz_bytes()); } RPCResponse::BeaconBlockHeaders(response) => { - s.append(response); + encoder.append(&response.as_ssz_bytes()); } RPCResponse::BeaconBlockBodies(response) => { - s.append(response); + encoder.append(&response.as_ssz_bytes()); } RPCResponse::BeaconChainState(response) => { - s.append(response); + encoder.append(&response.as_ssz_bytes()); } } } } + + // Finalize the encoder, writing to `buf`. + encoder.finalize(); } } diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index cd2c2269a..9cac12659 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Age Manning "] edition = "2018" [dev-dependencies] -test_harness = { path = "../beacon_chain/test_harness" } sloggers = "0.3.2" [dependencies] @@ -15,6 +14,7 @@ version = { path = "../version" } types = { path = "../../eth2/types" } slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] } ssz = { path = "../../eth2/utils/ssz" } +tree_hash = { path = "../../eth2/utils/tree_hash" } futures = "0.1.25" error-chain = "0.12.0" crossbeam-channel = "0.3.8" diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs index 827adeb3c..a98aa73de 100644 --- a/beacon_node/network/src/beacon_chain.rs +++ b/beacon_node/network/src/beacon_chain.rs @@ -8,19 +8,21 @@ use beacon_chain::{ AttestationValidationError, CheckPoint, }; use eth2_libp2p::rpc::HelloMessage; -use types::{Attestation, BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; +use types::{ + Attestation, BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Epoch, EthSpec, Hash256, Slot, +}; pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome, InvalidBlock}; /// The network's API to the beacon chain. -pub trait BeaconChain: Send + Sync { +pub trait BeaconChain: Send + Sync { fn get_spec(&self) -> &ChainSpec; - fn get_state(&self) -> RwLockReadGuard; + fn get_state(&self) -> RwLockReadGuard>; fn slot(&self) -> Slot; - fn head(&self) -> RwLockReadGuard; + fn head(&self) -> RwLockReadGuard>; fn get_block(&self, block_root: &Hash256) -> Result, BeaconChainError>; @@ -28,7 +30,7 @@ pub trait BeaconChain: Send + Sync { fn best_block_root(&self) -> Hash256; - fn finalized_head(&self) -> RwLockReadGuard; + fn finalized_head(&self) -> RwLockReadGuard>; fn finalized_epoch(&self) -> Epoch; @@ -62,17 +64,18 @@ pub trait BeaconChain: Send + Sync { fn is_new_block_root(&self, beacon_block_root: &Hash256) -> Result; } -impl BeaconChain for RawBeaconChain +impl BeaconChain for RawBeaconChain where T: ClientDB + Sized, U: SlotClock, F: ForkChoice, + E: EthSpec, { fn get_spec(&self) -> &ChainSpec { &self.spec } - fn get_state(&self) -> RwLockReadGuard { + fn get_state(&self) -> RwLockReadGuard> { self.state.read() } @@ -80,7 +83,7 @@ where self.get_state().slot } - fn head(&self) -> RwLockReadGuard { + fn head(&self) -> RwLockReadGuard> { self.head() } @@ -92,7 +95,7 @@ where self.get_state().finalized_epoch } - fn finalized_head(&self) -> RwLockReadGuard { + fn finalized_head(&self) -> RwLockReadGuard> { self.finalized_head() } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index c5ba25f82..a7d0ff2a1 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -13,6 +13,7 @@ use slog::{debug, warn}; use std::collections::HashMap; use std::sync::Arc; use std::time::Instant; +use types::EthSpec; /// Timeout for RPC requests. // const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); @@ -20,11 +21,11 @@ use std::time::Instant; // const HELLO_TIMEOUT: Duration = Duration::from_secs(30); /// Handles messages received from the network and client and organises syncing. -pub struct MessageHandler { +pub struct MessageHandler { /// Currently loaded and initialised beacon chain. - _chain: Arc, + _chain: Arc>, /// The syncing framework. - sync: SimpleSync, + sync: SimpleSync, /// The context required to send messages to, and process messages from peers. network_context: NetworkContext, /// The `MessageHandler` logger. @@ -44,10 +45,10 @@ pub enum HandlerMessage { PubsubMessage(PeerId, Box), } -impl MessageHandler { +impl MessageHandler { /// Initializes and runs the MessageHandler. pub fn spawn( - beacon_chain: Arc, + beacon_chain: Arc>, network_send: crossbeam_channel::Sender, executor: &tokio::runtime::TaskExecutor, log: slog::Logger, @@ -299,7 +300,7 @@ impl NetworkContext { let next_id = self .outgoing_request_ids .entry(peer_id.clone()) - .and_modify(|id| id.increment()) + .and_modify(RequestId::increment) .or_insert_with(|| RequestId::from(1)); next_id.previous() diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 06e3f7af9..50454a875 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -10,22 +10,23 @@ use futures::prelude::*; use futures::sync::oneshot; use futures::Stream; use slog::{debug, info, o, trace}; +use std::marker::PhantomData; use std::sync::Arc; use tokio::runtime::TaskExecutor; -use types::Topic; +use types::{EthSpec, Topic}; /// Service that handles communication between internal services and the eth2_libp2p network service. -pub struct Service { +pub struct Service { //libp2p_service: Arc>, _libp2p_exit: oneshot::Sender<()>, network_send: crossbeam_channel::Sender, - //message_handler: MessageHandler, - //message_handler_send: Sender, + _phantom: PhantomData, //message_handler: MessageHandler, + //message_handler_send: Sender } -impl Service { +impl Service { pub fn new( - beacon_chain: Arc, + beacon_chain: Arc>, config: &NetworkConfig, executor: &TaskExecutor, log: slog::Logger, @@ -56,6 +57,7 @@ impl Service { let network_service = Service { _libp2p_exit: libp2p_exit, network_send: network_send.clone(), + _phantom: PhantomData, }; Ok((Arc::new(network_service), network_send)) diff --git a/beacon_node/network/src/sync/import_queue.rs b/beacon_node/network/src/sync/import_queue.rs index 0026347eb..6c2fc33ee 100644 --- a/beacon_node/network/src/sync/import_queue.rs +++ b/beacon_node/network/src/sync/import_queue.rs @@ -2,10 +2,10 @@ use crate::beacon_chain::BeaconChain; use eth2_libp2p::rpc::methods::*; use eth2_libp2p::PeerId; use slog::{debug, error}; -use ssz::TreeHash; use std::sync::Arc; use std::time::{Duration, Instant}; -use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256, Slot}; +use tree_hash::TreeHash; +use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, EthSpec, Hash256, Slot}; /// Provides a queue for fully and partially built `BeaconBlock`s. /// @@ -15,12 +15,12 @@ use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256, Slot}; /// /// - When we receive a `BeaconBlockBody`, the only way we can find it's matching /// `BeaconBlockHeader` is to find a header such that `header.beacon_block_body == -/// hash_tree_root(body)`. Therefore, if we used a `HashMap` we would need to use the root of +/// tree_hash_root(body)`. Therefore, if we used a `HashMap` we would need to use the root of /// `BeaconBlockBody` as the key. /// - It is possible for multiple distinct blocks to have identical `BeaconBlockBodies`. Therefore /// we cannot use a `HashMap` keyed by the root of `BeaconBlockBody`. -pub struct ImportQueue { - pub chain: Arc, +pub struct ImportQueue { + pub chain: Arc>, /// Partially imported blocks, keyed by the root of `BeaconBlockBody`. pub partials: Vec, /// Time before a queue entry is considered state. @@ -29,9 +29,9 @@ pub struct ImportQueue { log: slog::Logger, } -impl ImportQueue { +impl ImportQueue { /// Return a new, empty queue. - pub fn new(chain: Arc, stale_time: Duration, log: slog::Logger) -> Self { + pub fn new(chain: Arc>, stale_time: Duration, log: slog::Logger) -> Self { Self { chain, partials: vec![], @@ -166,7 +166,7 @@ impl ImportQueue { let mut required_bodies: Vec = vec![]; for header in headers { - let block_root = Hash256::from_slice(&header.hash_tree_root()[..]); + let block_root = Hash256::from_slice(&header.tree_hash_root()[..]); if self.chain_has_not_seen_block(&block_root) { self.insert_header(block_root, header, sender.clone()); @@ -230,7 +230,7 @@ impl ImportQueue { /// /// If the body already existed, the `inserted` time is set to `now`. fn insert_body(&mut self, body: BeaconBlockBody, sender: PeerId) { - let body_root = Hash256::from_slice(&body.hash_tree_root()[..]); + let body_root = Hash256::from_slice(&body.tree_hash_root()[..]); self.partials.iter_mut().for_each(|mut p| { if let Some(header) = &mut p.header { @@ -250,7 +250,7 @@ impl ImportQueue { /// /// If the partial already existed, the `inserted` time is set to `now`. fn insert_full_block(&mut self, block: BeaconBlock, sender: PeerId) { - let block_root = Hash256::from_slice(&block.hash_tree_root()[..]); + let block_root = Hash256::from_slice(&block.tree_hash_root()[..]); let partial = PartialBeaconBlock { slot: block.slot, diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 824458b89..d44ffd4b7 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -5,11 +5,11 @@ use eth2_libp2p::rpc::methods::*; use eth2_libp2p::rpc::{RPCRequest, RPCResponse, RequestId}; use eth2_libp2p::PeerId; use slog::{debug, error, info, o, warn}; -use ssz::TreeHash; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use types::{Attestation, BeaconBlock, Epoch, Hash256, Slot}; +use tree_hash::TreeHash; +use types::{Attestation, BeaconBlock, Epoch, EthSpec, Hash256, Slot}; /// The number of slots that we can import blocks ahead of us, before going into full Sync mode. const SLOT_IMPORT_TOLERANCE: u64 = 100; @@ -88,8 +88,8 @@ impl From for PeerSyncInfo { } } -impl From<&Arc> for PeerSyncInfo { - fn from(chain: &Arc) -> PeerSyncInfo { +impl From<&Arc>> for PeerSyncInfo { + fn from(chain: &Arc>) -> PeerSyncInfo { Self::from(chain.hello_message()) } } @@ -103,22 +103,22 @@ pub enum SyncState { } /// Simple Syncing protocol. -pub struct SimpleSync { +pub struct SimpleSync { /// A reference to the underlying beacon chain. - chain: Arc, + chain: Arc>, /// A mapping of Peers to their respective PeerSyncInfo. known_peers: HashMap, /// A queue to allow importing of blocks - import_queue: ImportQueue, + import_queue: ImportQueue, /// The current state of the syncing protocol. state: SyncState, /// Sync logger. log: slog::Logger, } -impl SimpleSync { +impl SimpleSync { /// Instantiate a `SimpleSync` instance, with no peers and an empty queue. - pub fn new(beacon_chain: Arc, log: &slog::Logger) -> Self { + pub fn new(beacon_chain: Arc>, log: &slog::Logger) -> Self { let sync_logger = log.new(o!("Service"=> "Sync")); let queue_item_stale_time = Duration::from_secs(QUEUE_STALE_SECS); @@ -565,7 +565,7 @@ impl SimpleSync { return false; } - let block_root = Hash256::from_slice(&block.hash_tree_root()); + let block_root = Hash256::from_slice(&block.tree_hash_root()); // Ignore any block that the chain already knows about. if self.chain_has_seen_block(&block_root) { diff --git a/beacon_node/network/tests/tests.rs b/beacon_node/network/tests/tests.rs deleted file mode 100644 index 47d5482d3..000000000 --- a/beacon_node/network/tests/tests.rs +++ /dev/null @@ -1,570 +0,0 @@ -use crossbeam_channel::{unbounded, Receiver, RecvTimeoutError, Sender}; -use eth2_libp2p::rpc::methods::*; -use eth2_libp2p::rpc::{RPCMethod, RPCRequest, RPCResponse, RequestId}; -use eth2_libp2p::{PeerId, RPCEvent}; -use network::beacon_chain::BeaconChain as NetworkBeaconChain; -use network::message_handler::{HandlerMessage, MessageHandler}; -use network::service::{NetworkMessage, OutgoingMessage}; -use sloggers::terminal::{Destination, TerminalLoggerBuilder}; -use sloggers::types::Severity; -use sloggers::Build; -use std::time::Duration; -use test_harness::BeaconChainHarness; -use tokio::runtime::TaskExecutor; -use types::{test_utils::TestingBeaconStateBuilder, *}; - -pub struct SyncNode { - pub id: usize, - sender: Sender, - receiver: Receiver, - peer_id: PeerId, - harness: BeaconChainHarness, -} - -impl SyncNode { - fn from_beacon_state_builder( - id: usize, - executor: &TaskExecutor, - state_builder: TestingBeaconStateBuilder, - spec: &ChainSpec, - logger: slog::Logger, - ) -> Self { - let harness = BeaconChainHarness::from_beacon_state_builder(state_builder, spec.clone()); - - let (network_sender, network_receiver) = unbounded(); - let message_handler_sender = MessageHandler::spawn( - harness.beacon_chain.clone(), - network_sender, - executor, - logger, - ) - .unwrap(); - - Self { - id, - sender: message_handler_sender, - receiver: network_receiver, - peer_id: PeerId::random(), - harness, - } - } - - fn increment_beacon_chain_slot(&mut self) { - self.harness.increment_beacon_chain_slot(); - } - - fn send(&self, message: HandlerMessage) { - self.sender.send(message).unwrap(); - } - - fn recv(&self) -> Result { - self.receiver.recv_timeout(Duration::from_millis(500)) - } - - fn hello_message(&self) -> HelloMessage { - self.harness.beacon_chain.hello_message() - } - - pub fn connect_to(&mut self, node: &SyncNode) { - let message = HandlerMessage::PeerDialed(self.peer_id.clone()); - node.send(message); - } - - /// Reads the receive queue from one node and passes the message to the other. Also returns a - /// copy of the message. - /// - /// self -----> node - /// | - /// us - /// - /// Named after the unix `tee` command. - fn tee(&mut self, node: &SyncNode) -> NetworkMessage { - let network_message = self.recv().expect("Timeout on tee"); - - let handler_message = match network_message.clone() { - NetworkMessage::Send(_to_peer_id, OutgoingMessage::RPC(event)) => { - HandlerMessage::RPC(self.peer_id.clone(), event) - } - _ => panic!("tee cannot parse {:?}", network_message), - }; - - node.send(handler_message); - - network_message - } - - fn tee_hello_request(&mut self, node: &SyncNode) -> HelloMessage { - let request = self.tee_rpc_request(node); - - match request { - RPCRequest::Hello(message) => message, - _ => panic!("tee_hello_request got: {:?}", request), - } - } - - fn tee_hello_response(&mut self, node: &SyncNode) -> HelloMessage { - let response = self.tee_rpc_response(node); - - match response { - RPCResponse::Hello(message) => message, - _ => panic!("tee_hello_response got: {:?}", response), - } - } - - fn tee_block_root_request(&mut self, node: &SyncNode) -> BeaconBlockRootsRequest { - let msg = self.tee_rpc_request(node); - - match msg { - RPCRequest::BeaconBlockRoots(data) => data, - _ => panic!("tee_block_root_request got: {:?}", msg), - } - } - - fn tee_block_root_response(&mut self, node: &SyncNode) -> BeaconBlockRootsResponse { - let msg = self.tee_rpc_response(node); - - match msg { - RPCResponse::BeaconBlockRoots(data) => data, - _ => panic!("tee_block_root_response got: {:?}", msg), - } - } - - fn tee_block_header_request(&mut self, node: &SyncNode) -> BeaconBlockHeadersRequest { - let msg = self.tee_rpc_request(node); - - match msg { - RPCRequest::BeaconBlockHeaders(data) => data, - _ => panic!("tee_block_header_request got: {:?}", msg), - } - } - - fn tee_block_header_response(&mut self, node: &SyncNode) -> BeaconBlockHeadersResponse { - let msg = self.tee_rpc_response(node); - - match msg { - RPCResponse::BeaconBlockHeaders(data) => data, - _ => panic!("tee_block_header_response got: {:?}", msg), - } - } - - fn tee_block_body_request(&mut self, node: &SyncNode) -> BeaconBlockBodiesRequest { - let msg = self.tee_rpc_request(node); - - match msg { - RPCRequest::BeaconBlockBodies(data) => data, - _ => panic!("tee_block_body_request got: {:?}", msg), - } - } - - fn tee_block_body_response(&mut self, node: &SyncNode) -> BeaconBlockBodiesResponse { - let msg = self.tee_rpc_response(node); - - match msg { - RPCResponse::BeaconBlockBodies(data) => data, - _ => panic!("tee_block_body_response got: {:?}", msg), - } - } - - fn tee_rpc_request(&mut self, node: &SyncNode) -> RPCRequest { - let network_message = self.tee(node); - - match network_message { - NetworkMessage::Send( - _peer_id, - OutgoingMessage::RPC(RPCEvent::Request { - id: _, - method_id: _, - body, - }), - ) => body, - _ => panic!("tee_rpc_request failed! got {:?}", network_message), - } - } - - fn tee_rpc_response(&mut self, node: &SyncNode) -> RPCResponse { - let network_message = self.tee(node); - - match network_message { - NetworkMessage::Send( - _peer_id, - OutgoingMessage::RPC(RPCEvent::Response { - id: _, - method_id: _, - result, - }), - ) => result, - _ => panic!("tee_rpc_response failed! got {:?}", network_message), - } - } - - pub fn get_block_root_request(&self) -> BeaconBlockRootsRequest { - let request = self.recv_rpc_request().expect("No block root request"); - - match request { - RPCRequest::BeaconBlockRoots(request) => request, - _ => panic!("Did not get block root request"), - } - } - - pub fn get_block_headers_request(&self) -> BeaconBlockHeadersRequest { - let request = self.recv_rpc_request().expect("No block headers request"); - - match request { - RPCRequest::BeaconBlockHeaders(request) => request, - _ => panic!("Did not get block headers request"), - } - } - - pub fn get_block_bodies_request(&self) -> BeaconBlockBodiesRequest { - let request = self.recv_rpc_request().expect("No block bodies request"); - - match request { - RPCRequest::BeaconBlockBodies(request) => request, - _ => panic!("Did not get block bodies request"), - } - } - - fn _recv_rpc_response(&self) -> Result { - let network_message = self.recv()?; - Ok(match network_message { - NetworkMessage::Send( - _peer_id, - OutgoingMessage::RPC(RPCEvent::Response { - id: _, - method_id: _, - result, - }), - ) => result, - _ => panic!("get_rpc_response failed! got {:?}", network_message), - }) - } - - fn recv_rpc_request(&self) -> Result { - let network_message = self.recv()?; - Ok(match network_message { - NetworkMessage::Send( - _peer_id, - OutgoingMessage::RPC(RPCEvent::Request { - id: _, - method_id: _, - body, - }), - ) => body, - _ => panic!("get_rpc_request failed! got {:?}", network_message), - }) - } -} - -fn get_logger() -> slog::Logger { - let mut builder = TerminalLoggerBuilder::new(); - builder.level(Severity::Debug); - builder.destination(Destination::Stderr); - builder.build().unwrap() -} - -pub struct SyncMaster { - harness: BeaconChainHarness, - peer_id: PeerId, - response_ids: Vec, -} - -impl SyncMaster { - fn from_beacon_state_builder( - state_builder: TestingBeaconStateBuilder, - node_count: usize, - spec: &ChainSpec, - ) -> Self { - let harness = BeaconChainHarness::from_beacon_state_builder(state_builder, spec.clone()); - let peer_id = PeerId::random(); - let response_ids = vec![RequestId::from(0); node_count]; - - Self { - harness, - peer_id, - response_ids, - } - } - - pub fn response_id(&mut self, node: &SyncNode) -> RequestId { - let id = self.response_ids[node.id].clone(); - self.response_ids[node.id].increment(); - id - } - - pub fn do_hello_with(&mut self, node: &SyncNode) { - let message = HandlerMessage::PeerDialed(self.peer_id.clone()); - node.send(message); - - let request = node.recv_rpc_request().expect("No hello response"); - - match request { - RPCRequest::Hello(_hello) => { - let hello = self.harness.beacon_chain.hello_message(); - let response = self.rpc_response(node, RPCResponse::Hello(hello)); - node.send(response); - } - _ => panic!("Got message other than hello from node."), - } - } - - pub fn respond_to_block_roots_request( - &mut self, - node: &SyncNode, - request: BeaconBlockRootsRequest, - ) { - let roots = self - .harness - .beacon_chain - .get_block_roots(request.start_slot, request.count as usize, 0) - .expect("Beacon chain did not give block roots") - .iter() - .enumerate() - .map(|(i, root)| BlockRootSlot { - block_root: *root, - slot: Slot::from(i) + request.start_slot, - }) - .collect(); - - let response = RPCResponse::BeaconBlockRoots(BeaconBlockRootsResponse { roots }); - self.send_rpc_response(node, response) - } - - pub fn respond_to_block_headers_request( - &mut self, - node: &SyncNode, - request: BeaconBlockHeadersRequest, - ) { - let roots = self - .harness - .beacon_chain - .get_block_roots( - request.start_slot, - request.max_headers as usize, - request.skip_slots as usize, - ) - .expect("Beacon chain did not give blocks"); - - if roots.is_empty() { - panic!("Roots was empty when trying to get headers.") - } - - assert_eq!( - roots[0], request.start_root, - "Got the wrong start root when getting headers" - ); - - let headers: Vec = roots - .iter() - .map(|root| { - let block = self - .harness - .beacon_chain - .get_block(root) - .expect("Failed to load block") - .expect("Block did not exist"); - block.block_header() - }) - .collect(); - - let response = RPCResponse::BeaconBlockHeaders(BeaconBlockHeadersResponse { headers }); - self.send_rpc_response(node, response) - } - - pub fn respond_to_block_bodies_request( - &mut self, - node: &SyncNode, - request: BeaconBlockBodiesRequest, - ) { - let block_bodies: Vec = request - .block_roots - .iter() - .map(|root| { - let block = self - .harness - .beacon_chain - .get_block(root) - .expect("Failed to load block") - .expect("Block did not exist"); - block.body - }) - .collect(); - - let response = RPCResponse::BeaconBlockBodies(BeaconBlockBodiesResponse { block_bodies }); - self.send_rpc_response(node, response) - } - - fn send_rpc_response(&mut self, node: &SyncNode, rpc_response: RPCResponse) { - node.send(self.rpc_response(node, rpc_response)); - } - - fn rpc_response(&mut self, node: &SyncNode, rpc_response: RPCResponse) -> HandlerMessage { - HandlerMessage::RPC( - self.peer_id.clone(), - RPCEvent::Response { - id: self.response_id(node), - method_id: RPCMethod::Hello.into(), - result: rpc_response, - }, - ) - } -} - -fn test_setup( - state_builder: TestingBeaconStateBuilder, - node_count: usize, - spec: &ChainSpec, - logger: slog::Logger, -) -> (tokio::runtime::Runtime, SyncMaster, Vec) { - let runtime = tokio::runtime::Runtime::new().unwrap(); - - let mut nodes = Vec::with_capacity(node_count); - for id in 0..node_count { - let node = SyncNode::from_beacon_state_builder( - id, - &runtime.executor(), - state_builder.clone(), - &spec, - logger.clone(), - ); - - nodes.push(node); - } - - let master = SyncMaster::from_beacon_state_builder(state_builder, node_count, &spec); - - (runtime, master, nodes) -} - -pub fn build_blocks(blocks: usize, master: &mut SyncMaster, nodes: &mut Vec) { - for _ in 0..blocks { - master.harness.advance_chain_with_block(); - for i in 0..nodes.len() { - nodes[i].increment_beacon_chain_slot(); - } - } - master.harness.run_fork_choice(); - - for i in 0..nodes.len() { - nodes[i].harness.run_fork_choice(); - } -} - -#[test] -#[ignore] -fn sync_node_with_master() { - let logger = get_logger(); - let spec = ChainSpec::few_validators(); - let validator_count = 8; - let node_count = 1; - - let state_builder = - TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, &spec); - - let (runtime, mut master, mut nodes) = - test_setup(state_builder, node_count, &spec, logger.clone()); - - let original_node_slot = nodes[0].hello_message().best_slot; - - build_blocks(2, &mut master, &mut nodes); - - master.do_hello_with(&nodes[0]); - - let roots_request = nodes[0].get_block_root_request(); - assert_eq!(roots_request.start_slot, original_node_slot + 1); - assert_eq!(roots_request.count, 2); - - master.respond_to_block_roots_request(&nodes[0], roots_request); - - let headers_request = nodes[0].get_block_headers_request(); - assert_eq!(headers_request.start_slot, original_node_slot + 1); - assert_eq!(headers_request.max_headers, 2); - assert_eq!(headers_request.skip_slots, 0); - - master.respond_to_block_headers_request(&nodes[0], headers_request); - - let bodies_request = nodes[0].get_block_bodies_request(); - assert_eq!(bodies_request.block_roots.len(), 2); - - master.respond_to_block_bodies_request(&nodes[0], bodies_request); - - std::thread::sleep(Duration::from_millis(10000)); - runtime.shutdown_now(); -} - -#[test] -#[ignore] -fn sync_two_nodes() { - let logger = get_logger(); - let spec = ChainSpec::few_validators(); - let validator_count = 8; - let node_count = 2; - - let state_builder = - TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, &spec); - - let (runtime, _master, mut nodes) = - test_setup(state_builder, node_count, &spec, logger.clone()); - - // let original_node_slot = nodes[0].hello_message().best_slot; - let mut node_a = nodes.remove(0); - let mut node_b = nodes.remove(0); - - let blocks = 2; - - // Node A builds out a longer, better chain. - for _ in 0..blocks { - // Node A should build a block. - node_a.harness.advance_chain_with_block(); - // Node B should just increment it's slot without a block. - node_b.harness.increment_beacon_chain_slot(); - } - node_a.harness.run_fork_choice(); - - // A connects to B. - node_a.connect_to(&node_b); - - // B says hello to A. - node_b.tee_hello_request(&node_a); - // A says hello back. - node_a.tee_hello_response(&node_b); - - // B requests block roots from A. - node_b.tee_block_root_request(&node_a); - // A provides block roots to A. - node_a.tee_block_root_response(&node_b); - - // B requests block headers from A. - node_b.tee_block_header_request(&node_a); - // A provides block headers to B. - node_a.tee_block_header_response(&node_b); - - // B requests block bodies from A. - node_b.tee_block_body_request(&node_a); - // A provides block bodies to B. - node_a.tee_block_body_response(&node_b); - - std::thread::sleep(Duration::from_secs(20)); - - node_b.harness.run_fork_choice(); - - let node_a_chain = node_a - .harness - .beacon_chain - .chain_dump() - .expect("Can't dump node a chain"); - - let node_b_chain = node_b - .harness - .beacon_chain - .chain_dump() - .expect("Can't dump node b chain"); - - assert_eq!( - node_a_chain.len(), - node_b_chain.len(), - "Chains should be equal length" - ); - assert_eq!(node_a_chain, node_b_chain, "Chains should be identical"); - - runtime.shutdown_now(); -} diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index 3abfdac59..e22715b55 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -7,17 +7,17 @@ use protos::services::{ }; use protos::services_grpc::AttestationService; use slog::{error, info, trace, warn}; -use ssz::{ssz_encode, Decodable}; +use ssz::{ssz_encode, Decode}; use std::sync::Arc; -use types::Attestation; +use types::{Attestation, EthSpec}; #[derive(Clone)] -pub struct AttestationServiceInstance { - pub chain: Arc, +pub struct AttestationServiceInstance { + pub chain: Arc>, pub log: slog::Logger, } -impl AttestationService for AttestationServiceInstance { +impl AttestationService for AttestationServiceInstance { /// Produce the `AttestationData` for signing by a validator. fn produce_attestation_data( &mut self, @@ -110,8 +110,8 @@ impl AttestationService for AttestationServiceInstance { let mut resp = PublishAttestationResponse::new(); let ssz_serialized_attestation = req.get_attestation().get_ssz(); - let attestation = match Attestation::ssz_decode(ssz_serialized_attestation, 0) { - Ok((v, _index)) => v, + let attestation = match Attestation::from_ssz_bytes(ssz_serialized_attestation) { + Ok(v) => v, Err(_) => { let log_clone = self.log.clone(); let f = sink diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index 450bcbca1..bbe6a8ee2 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -11,18 +11,18 @@ use protos::services::{ use protos::services_grpc::BeaconBlockService; use slog::Logger; use slog::{error, info, trace, warn}; -use ssz::{ssz_encode, Decodable}; +use ssz::{ssz_encode, Decode}; use std::sync::Arc; -use types::{BeaconBlock, Signature, Slot}; +use types::{BeaconBlock, EthSpec, Signature, Slot}; #[derive(Clone)] -pub struct BeaconBlockServiceInstance { - pub chain: Arc, +pub struct BeaconBlockServiceInstance { + pub chain: Arc>, pub network_chan: crossbeam_channel::Sender, pub log: Logger, } -impl BeaconBlockService for BeaconBlockServiceInstance { +impl BeaconBlockService for BeaconBlockServiceInstance { /// Produce a `BeaconBlock` for signing by a validator. fn produce_beacon_block( &mut self, @@ -35,8 +35,8 @@ impl BeaconBlockService for BeaconBlockServiceInstance { // decode the request // TODO: requested slot currently unused, see: https://github.com/sigp/lighthouse/issues/336 let _requested_slot = Slot::from(req.get_slot()); - let randao_reveal = match Signature::ssz_decode(req.get_randao_reveal(), 0) { - Ok((reveal, _index)) => reveal, + let randao_reveal = match Signature::from_ssz_bytes(req.get_randao_reveal()) { + Ok(reveal) => reveal, Err(_) => { // decode error, incorrect signature let log_clone = self.log.clone(); @@ -91,8 +91,8 @@ impl BeaconBlockService for BeaconBlockServiceInstance { let ssz_serialized_block = req.get_block().get_ssz(); - match BeaconBlock::ssz_decode(ssz_serialized_block, 0) { - Ok((block, _i)) => { + match BeaconBlock::from_ssz_bytes(ssz_serialized_block) { + Ok(block) => { match self.chain.process_block(block.clone()) { Ok(outcome) => { if outcome.sucessfully_processed() { diff --git a/beacon_node/rpc/src/beacon_chain.rs b/beacon_node/rpc/src/beacon_chain.rs index ddc91b73c..7e75b32ce 100644 --- a/beacon_node/rpc/src/beacon_chain.rs +++ b/beacon_node/rpc/src/beacon_chain.rs @@ -8,15 +8,15 @@ use beacon_chain::{ AttestationValidationError, BlockProductionError, }; pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome}; -use types::{Attestation, AttestationData, BeaconBlock}; +use types::{Attestation, AttestationData, BeaconBlock, EthSpec}; /// The RPC's API to the beacon chain. -pub trait BeaconChain: Send + Sync { +pub trait BeaconChain: Send + Sync { fn get_spec(&self) -> &ChainSpec; - fn get_state(&self) -> RwLockReadGuard; + fn get_state(&self) -> RwLockReadGuard>; - fn get_mut_state(&self) -> RwLockWriteGuard; + fn get_mut_state(&self) -> RwLockWriteGuard>; fn process_block(&self, block: BeaconBlock) -> Result; @@ -24,7 +24,7 @@ pub trait BeaconChain: Send + Sync { fn produce_block( &self, randao_reveal: Signature, - ) -> Result<(BeaconBlock, BeaconState), BlockProductionError>; + ) -> Result<(BeaconBlock, BeaconState), BlockProductionError>; fn produce_attestation_data(&self, shard: u64) -> Result; @@ -34,21 +34,22 @@ pub trait BeaconChain: Send + Sync { ) -> Result<(), AttestationValidationError>; } -impl BeaconChain for RawBeaconChain +impl BeaconChain for RawBeaconChain where T: ClientDB + Sized, U: SlotClock, F: ForkChoice, + E: EthSpec, { fn get_spec(&self) -> &ChainSpec { &self.spec } - fn get_state(&self) -> RwLockReadGuard { + fn get_state(&self) -> RwLockReadGuard> { self.state.read() } - fn get_mut_state(&self) -> RwLockWriteGuard { + fn get_mut_state(&self) -> RwLockWriteGuard> { self.state.write() } @@ -62,7 +63,7 @@ where fn produce_block( &self, randao_reveal: Signature, - ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { + ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { self.produce_block(randao_reveal) } diff --git a/beacon_node/rpc/src/beacon_node.rs b/beacon_node/rpc/src/beacon_node.rs index a9b8df343..2ca39ae51 100644 --- a/beacon_node/rpc/src/beacon_node.rs +++ b/beacon_node/rpc/src/beacon_node.rs @@ -5,14 +5,15 @@ use protos::services::{Empty, Fork, NodeInfoResponse}; use protos::services_grpc::BeaconNodeService; use slog::{trace, warn}; use std::sync::Arc; +use types::EthSpec; #[derive(Clone)] -pub struct BeaconNodeServiceInstance { - pub chain: Arc, +pub struct BeaconNodeServiceInstance { + pub chain: Arc>, pub log: slog::Logger, } -impl BeaconNodeService for BeaconNodeServiceInstance { +impl BeaconNodeService for BeaconNodeServiceInstance { /// Provides basic node information. fn info(&mut self, ctx: RpcContext, _req: Empty, sink: UnarySink) { trace!(self.log, "Node info requested via RPC"); diff --git a/beacon_node/rpc/src/lib.rs b/beacon_node/rpc/src/lib.rs index 5aac4ce55..f1d5e9c88 100644 --- a/beacon_node/rpc/src/lib.rs +++ b/beacon_node/rpc/src/lib.rs @@ -21,12 +21,13 @@ use protos::services_grpc::{ use slog::{info, o, warn}; use std::sync::Arc; use tokio::runtime::TaskExecutor; +use types::EthSpec; -pub fn start_server( +pub fn start_server( config: &RPCConfig, executor: &TaskExecutor, network_chan: crossbeam_channel::Sender, - beacon_chain: Arc, + beacon_chain: Arc>, log: &slog::Logger, ) -> exit_future::Signal { let log = log.new(o!("Service"=>"RPC")); diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index 4bef1e2e6..34fbba5c4 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -5,18 +5,18 @@ use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; use protos::services::{ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty}; use protos::services_grpc::ValidatorService; use slog::{trace, warn}; -use ssz::decode; +use ssz::Decode; use std::sync::Arc; -use types::{Epoch, RelativeEpoch}; +use types::{Epoch, EthSpec, RelativeEpoch}; #[derive(Clone)] -pub struct ValidatorServiceInstance { - pub chain: Arc, +pub struct ValidatorServiceInstance { + pub chain: Arc>, pub log: slog::Logger, } //TODO: Refactor Errors -impl ValidatorService for ValidatorServiceInstance { +impl ValidatorService for ValidatorServiceInstance { /// For a list of validator public keys, this function returns the slot at which each /// validator must propose a block, attest to a shard, their shard committee and the shard they /// need to attest to. @@ -74,7 +74,7 @@ impl ValidatorService for ValidatorServiceInstance { for validator_pk in validators.get_public_keys() { let mut active_validator = ActiveValidator::new(); - let public_key = match decode::(validator_pk) { + let public_key = match PublicKey::from_ssz_bytes(validator_pk) { Ok(v) => v, Err(_) => { let log_clone = self.log.clone(); diff --git a/docs/documentation.md b/docs/documentation.md new file mode 100644 index 000000000..360055887 --- /dev/null +++ b/docs/documentation.md @@ -0,0 +1,14 @@ +# Lighthouse Technical Documentation + +The technical documentation, as generated by Rust, is available at [lighthouse-docs.sigmaprime.io](http://lighthouse-docs.sigmaprime.io/). + +This documentation is generated from Lighthouse and updated regularly. + + +### How to update: + +- `cargo doc`: builds the docs inside the `target/doc/` directory. +- `aws s3 sync target/doc/ s3://lighthouse-docs.sigmaprime.io/`: Uploads all of the docs, as generated with `cargo doc`, to the S3 bucket. + +**Note**: You will need appropriate credentials to make the upload. + diff --git a/eth2/README.md b/eth2/README.md index cf041e987..2159e2fd3 100644 --- a/eth2/README.md +++ b/eth2/README.md @@ -30,7 +30,7 @@ Rust crates containing logic common across the Lighthouse project. - [`ssz`](utils/ssz/): an implementation of the SimpleSerialize serialization/deserialization protocol used by Eth 2.0. - [`ssz_derive`](utils/ssz_derive/): provides procedural macros for - deriving SSZ `Encodable`, `Decodable`, and `TreeHash` methods. + deriving SSZ `Encode`, `Decode`, and `TreeHash` methods. - [`swap_or_not_shuffle`](utils/swap_or_not_shuffle/): a list-shuffling method which is slow, but allows for a subset of indices to be shuffled. - [`test_random_derive`](utils/test_random_derive/): provides procedural diff --git a/eth2/attester/Cargo.toml b/eth2/attester/Cargo.toml deleted file mode 100644 index 956ecf565..000000000 --- a/eth2/attester/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "attester" -version = "0.1.0" -authors = ["Paul Hauner "] -edition = "2018" - -[dependencies] -slot_clock = { path = "../../eth2/utils/slot_clock" } -ssz = { path = "../../eth2/utils/ssz" } -types = { path = "../../eth2/types" } diff --git a/eth2/attester/src/lib.rs b/eth2/attester/src/lib.rs deleted file mode 100644 index a4295f005..000000000 --- a/eth2/attester/src/lib.rs +++ /dev/null @@ -1,257 +0,0 @@ -pub mod test_utils; -mod traits; - -use slot_clock::SlotClock; -use ssz::TreeHash; -use std::sync::Arc; -use types::{AttestationData, AttestationDataAndCustodyBit, FreeAttestation, Signature, Slot}; - -pub use self::traits::{ - BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, -}; - -const PHASE_0_CUSTODY_BIT: bool = false; -const DOMAIN_ATTESTATION: u64 = 1; - -#[derive(Debug, PartialEq)] -pub enum PollOutcome { - AttestationProduced(Slot), - AttestationNotRequired(Slot), - SlashableAttestationNotProduced(Slot), - BeaconNodeUnableToProduceAttestation(Slot), - ProducerDutiesUnknown(Slot), - SlotAlreadyProcessed(Slot), - SignerRejection(Slot), - ValidatorIsUnknown(Slot), -} - -#[derive(Debug, PartialEq)] -pub enum Error { - SlotClockError, - SlotUnknowable, - EpochMapPoisoned, - SlotClockPoisoned, - EpochLengthIsZero, - BeaconNodeError(BeaconNodeError), -} - -/// A polling state machine which performs block production duties, based upon some epoch duties -/// (`EpochDutiesMap`) and a concept of time (`SlotClock`). -/// -/// Ensures that messages are not slashable. -/// -/// Relies upon an external service to keep the `EpochDutiesMap` updated. -pub struct Attester { - pub last_processed_slot: Option, - duties: Arc, - slot_clock: Arc, - beacon_node: Arc, - signer: Arc, -} - -impl Attester { - /// Returns a new instance where `last_processed_slot == 0`. - pub fn new(duties: Arc, slot_clock: Arc, beacon_node: Arc, signer: Arc) -> Self { - Self { - last_processed_slot: None, - duties, - slot_clock, - beacon_node, - signer, - } - } -} - -impl Attester { - /// Poll the `BeaconNode` and produce an attestation if required. - pub fn poll(&mut self) -> Result { - let slot = self - .slot_clock - .present_slot() - .map_err(|_| Error::SlotClockError)? - .ok_or(Error::SlotUnknowable)?; - - if !self.is_processed_slot(slot) { - self.last_processed_slot = Some(slot); - - let shard = match self.duties.attestation_shard(slot) { - Ok(Some(result)) => result, - Ok(None) => return Ok(PollOutcome::AttestationNotRequired(slot)), - Err(DutiesReaderError::UnknownEpoch) => { - return Ok(PollOutcome::ProducerDutiesUnknown(slot)); - } - Err(DutiesReaderError::UnknownValidator) => { - return Ok(PollOutcome::ValidatorIsUnknown(slot)); - } - Err(DutiesReaderError::EpochLengthIsZero) => return Err(Error::EpochLengthIsZero), - Err(DutiesReaderError::Poisoned) => return Err(Error::EpochMapPoisoned), - }; - - self.produce_attestation(slot, shard) - } else { - Ok(PollOutcome::SlotAlreadyProcessed(slot)) - } - } - - fn produce_attestation(&mut self, slot: Slot, shard: u64) -> Result { - let attestation_data = match self.beacon_node.produce_attestation_data(slot, shard)? { - Some(attestation_data) => attestation_data, - None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)), - }; - - if !self.safe_to_produce(&attestation_data) { - return Ok(PollOutcome::SlashableAttestationNotProduced(slot)); - } - - let signature = match self.sign_attestation_data(&attestation_data) { - Some(signature) => signature, - None => return Ok(PollOutcome::SignerRejection(slot)), - }; - - let validator_index = match self.duties.validator_index() { - Some(validator_index) => validator_index, - None => return Ok(PollOutcome::ValidatorIsUnknown(slot)), - }; - - let free_attestation = FreeAttestation { - data: attestation_data, - signature, - validator_index, - }; - - self.beacon_node.publish_attestation(free_attestation)?; - Ok(PollOutcome::AttestationProduced(slot)) - } - - fn is_processed_slot(&self, slot: Slot) -> bool { - match self.last_processed_slot { - Some(processed_slot) if slot <= processed_slot => true, - _ => false, - } - } - - /// Consumes a block, returning that block signed by the validators private key. - /// - /// Important: this function will not check to ensure the block is not slashable. This must be - /// done upstream. - fn sign_attestation_data(&mut self, attestation_data: &AttestationData) -> Option { - self.store_produce(attestation_data); - - let message = AttestationDataAndCustodyBit { - data: attestation_data.clone(), - custody_bit: PHASE_0_CUSTODY_BIT, - } - .hash_tree_root(); - - self.signer - .sign_attestation_message(&message[..], DOMAIN_ATTESTATION) - } - - /// Returns `true` if signing some attestation_data is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _attestation_data: &AttestationData) -> bool { - // TODO: ensure the producer doesn't produce slashable blocks. - // https://github.com/sigp/lighthouse/issues/160 - true - } - - /// Record that a block was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &AttestationData) { - // TODO: record this block production to prevent future slashings. - // https://github.com/sigp/lighthouse/issues/160 - } -} - -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) - } -} - -#[cfg(test)] -mod tests { - use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; - use super::*; - use slot_clock::TestingSlotClock; - use types::{ - test_utils::{SeedableRng, TestRandom, XorShiftRng}, - ChainSpec, Keypair, - }; - - // TODO: implement more thorough testing. - // https://github.com/sigp/lighthouse/issues/160 - // - // These tests should serve as a good example for future tests. - - #[test] - pub fn polling() { - let mut rng = XorShiftRng::from_seed([42; 16]); - - let spec = Arc::new(ChainSpec::foundation()); - let slot_clock = Arc::new(TestingSlotClock::new(0)); - let beacon_node = Arc::new(SimulatedBeaconNode::default()); - let signer = Arc::new(LocalSigner::new(Keypair::random())); - - let mut duties = EpochMap::new(spec.slots_per_epoch); - let attest_slot = Slot::new(100); - let attest_epoch = attest_slot / spec.slots_per_epoch; - let attest_shard = 12; - duties.insert_attestation_shard(attest_slot, attest_shard); - duties.set_validator_index(Some(2)); - let duties = Arc::new(duties); - - let mut attester = Attester::new( - duties.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - // Configure responses from the BeaconNode. - beacon_node.set_next_produce_result(Ok(Some(AttestationData::random_for_test(&mut rng)))); - beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidAttestation)); - - // One slot before attestation slot... - slot_clock.set_slot(attest_slot.as_u64() - 1); - assert_eq!( - attester.poll(), - Ok(PollOutcome::AttestationNotRequired(attest_slot - 1)) - ); - - // On the attest slot... - slot_clock.set_slot(attest_slot.as_u64()); - assert_eq!( - attester.poll(), - Ok(PollOutcome::AttestationProduced(attest_slot)) - ); - - // Trying the same attest slot again... - slot_clock.set_slot(attest_slot.as_u64()); - assert_eq!( - attester.poll(), - Ok(PollOutcome::SlotAlreadyProcessed(attest_slot)) - ); - - // One slot after the attest slot... - slot_clock.set_slot(attest_slot.as_u64() + 1); - assert_eq!( - attester.poll(), - Ok(PollOutcome::AttestationNotRequired(attest_slot + 1)) - ); - - // In an epoch without known duties... - let slot = (attest_epoch + 1) * spec.slots_per_epoch; - slot_clock.set_slot(slot.into()); - assert_eq!( - attester.poll(), - Ok(PollOutcome::ProducerDutiesUnknown(slot)) - ); - } -} diff --git a/eth2/attester/src/test_utils/epoch_map.rs b/eth2/attester/src/test_utils/epoch_map.rs deleted file mode 100644 index 0b5827d64..000000000 --- a/eth2/attester/src/test_utils/epoch_map.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{DutiesReader, DutiesReaderError}; -use std::collections::HashMap; -use types::{Epoch, Slot}; - -pub struct EpochMap { - slots_per_epoch: u64, - validator_index: Option, - map: HashMap, -} - -impl EpochMap { - pub fn new(slots_per_epoch: u64) -> Self { - Self { - slots_per_epoch, - validator_index: None, - map: HashMap::new(), - } - } - - pub fn insert_attestation_shard(&mut self, slot: Slot, shard: u64) { - let epoch = slot.epoch(self.slots_per_epoch); - self.map.insert(epoch, (slot, shard)); - } - - pub fn set_validator_index(&mut self, index: Option) { - self.validator_index = index; - } -} - -impl DutiesReader for EpochMap { - fn attestation_shard(&self, slot: Slot) -> Result, DutiesReaderError> { - let epoch = slot.epoch(self.slots_per_epoch); - - match self.map.get(&epoch) { - Some((attest_slot, attest_shard)) if *attest_slot == slot => Ok(Some(*attest_shard)), - Some((attest_slot, _attest_shard)) if *attest_slot != slot => Ok(None), - _ => Err(DutiesReaderError::UnknownEpoch), - } - } - - fn validator_index(&self) -> Option { - self.validator_index - } -} diff --git a/eth2/attester/src/test_utils/local_signer.rs b/eth2/attester/src/test_utils/local_signer.rs deleted file mode 100644 index 896d90775..000000000 --- a/eth2/attester/src/test_utils/local_signer.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::traits::Signer; -use std::sync::RwLock; -use types::{Keypair, Signature}; - -/// A test-only struct used to simulate a Beacon Node. -pub struct LocalSigner { - keypair: Keypair, - should_sign: RwLock, -} - -impl LocalSigner { - /// Produce a new LocalSigner with signing enabled by default. - pub fn new(keypair: Keypair) -> Self { - Self { - keypair, - should_sign: RwLock::new(true), - } - } - - /// If set to `false`, the service will refuse to sign all messages. Otherwise, all messages - /// will be signed. - pub fn enable_signing(&self, enabled: bool) { - *self.should_sign.write().unwrap() = enabled; - } -} - -impl Signer for LocalSigner { - fn sign_attestation_message(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.keypair.sk)) - } -} diff --git a/eth2/attester/src/test_utils/mod.rs b/eth2/attester/src/test_utils/mod.rs deleted file mode 100644 index 481247dd0..000000000 --- a/eth2/attester/src/test_utils/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod epoch_map; -mod local_signer; -mod simulated_beacon_node; - -pub use self::epoch_map::EpochMap; -pub use self::local_signer::LocalSigner; -pub use self::simulated_beacon_node::SimulatedBeaconNode; diff --git a/eth2/attester/src/test_utils/simulated_beacon_node.rs b/eth2/attester/src/test_utils/simulated_beacon_node.rs deleted file mode 100644 index d19f43422..000000000 --- a/eth2/attester/src/test_utils/simulated_beacon_node.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome}; -use std::sync::RwLock; -use types::{AttestationData, FreeAttestation, Slot}; - -type ProduceResult = Result, BeaconNodeError>; -type PublishResult = Result; - -/// A test-only struct used to simulate a Beacon Node. -#[derive(Default)] -pub struct SimulatedBeaconNode { - pub produce_input: RwLock>, - pub produce_result: RwLock>, - - pub publish_input: RwLock>, - pub publish_result: RwLock>, -} - -impl SimulatedBeaconNode { - pub fn set_next_produce_result(&self, result: ProduceResult) { - *self.produce_result.write().unwrap() = Some(result); - } - - pub fn set_next_publish_result(&self, result: PublishResult) { - *self.publish_result.write().unwrap() = Some(result); - } -} - -impl BeaconNode for SimulatedBeaconNode { - fn produce_attestation_data(&self, slot: Slot, shard: u64) -> ProduceResult { - *self.produce_input.write().unwrap() = Some((slot, shard)); - match *self.produce_result.read().unwrap() { - Some(ref r) => r.clone(), - None => panic!("TestBeaconNode: produce_result == None"), - } - } - - fn publish_attestation(&self, free_attestation: FreeAttestation) -> PublishResult { - *self.publish_input.write().unwrap() = Some(free_attestation.clone()); - match *self.publish_result.read().unwrap() { - Some(ref r) => r.clone(), - None => panic!("TestBeaconNode: publish_result == None"), - } - } -} diff --git a/eth2/attester/src/traits.rs b/eth2/attester/src/traits.rs deleted file mode 100644 index 2fd6940af..000000000 --- a/eth2/attester/src/traits.rs +++ /dev/null @@ -1,49 +0,0 @@ -use types::{AttestationData, FreeAttestation, Signature, Slot}; - -#[derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeError { - RemoteFailure(String), - DecodeFailure, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum PublishOutcome { - ValidAttestation, - InvalidAttestation(String), -} - -/// Defines the methods required to produce and publish blocks on a Beacon Node. -pub trait BeaconNode: Send + Sync { - fn produce_attestation_data( - &self, - slot: Slot, - shard: u64, - ) -> Result, BeaconNodeError>; - - fn publish_attestation( - &self, - free_attestation: FreeAttestation, - ) -> Result; -} - -#[derive(Debug, PartialEq, Clone)] -pub enum DutiesReaderError { - UnknownValidator, - UnknownEpoch, - EpochLengthIsZero, - Poisoned, -} - -/// Informs a validator of their duties (e.g., block production). -pub trait DutiesReader: Send + Sync { - /// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.` - fn attestation_shard(&self, slot: Slot) -> Result, DutiesReaderError>; - - /// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.` - fn validator_index(&self) -> Option; -} - -/// Signs message using an internally-maintained private key. -pub trait Signer { - fn sign_attestation_message(&self, message: &[u8], domain: u64) -> Option; -} diff --git a/eth2/block_proposer/Cargo.toml b/eth2/block_proposer/Cargo.toml deleted file mode 100644 index 81f1ccc28..000000000 --- a/eth2/block_proposer/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "block_proposer" -version = "0.1.0" -authors = ["Paul Hauner "] -edition = "2018" - -[dependencies] -int_to_bytes = { path = "../utils/int_to_bytes" } -slot_clock = { path = "../utils/slot_clock" } -ssz = { path = "../utils/ssz" } -types = { path = "../types" } diff --git a/eth2/block_proposer/src/lib.rs b/eth2/block_proposer/src/lib.rs deleted file mode 100644 index e62c4b71d..000000000 --- a/eth2/block_proposer/src/lib.rs +++ /dev/null @@ -1,303 +0,0 @@ -pub mod test_utils; -mod traits; - -use slot_clock::SlotClock; -use ssz::{SignedRoot, TreeHash}; -use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Slot}; - -pub use self::traits::{ - BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, -}; - -#[derive(Debug, PartialEq)] -pub enum PollOutcome { - /// A new block was produced. - BlockProduced(Slot), - /// A block was not produced as it would have been slashable. - SlashableBlockNotProduced(Slot), - /// The validator duties did not require a block to be produced. - BlockProductionNotRequired(Slot), - /// The duties for the present epoch were not found. - ProducerDutiesUnknown(Slot), - /// The slot has already been processed, execution was skipped. - SlotAlreadyProcessed(Slot), - /// The Beacon Node was unable to produce a block at that slot. - BeaconNodeUnableToProduceBlock(Slot), - /// The signer failed to sign the message. - SignerRejection(Slot), - /// The public key for this validator is not an active validator. - ValidatorIsUnknown(Slot), - /// Unable to determine a `Fork` for signature domain generation. - UnableToGetFork(Slot), -} - -#[derive(Debug, PartialEq)] -pub enum Error { - SlotClockError, - SlotUnknowable, - EpochMapPoisoned, - SlotClockPoisoned, - EpochLengthIsZero, - BeaconNodeError(BeaconNodeError), -} - -/// A polling state machine which performs block production duties, based upon some epoch duties -/// (`EpochDutiesMap`) and a concept of time (`SlotClock`). -/// -/// Ensures that messages are not slashable. -/// -/// Relies upon an external service to keep the `EpochDutiesMap` updated. -pub struct BlockProducer { - pub last_processed_slot: Option, - spec: Arc, - epoch_map: Arc, - slot_clock: Arc, - beacon_node: Arc, - signer: Arc, -} - -impl BlockProducer { - /// Returns a new instance where `last_processed_slot == 0`. - pub fn new( - spec: Arc, - epoch_map: Arc, - slot_clock: Arc, - beacon_node: Arc, - signer: Arc, - ) -> Self { - Self { - last_processed_slot: None, - spec, - epoch_map, - slot_clock, - beacon_node, - signer, - } - } -} - -impl BlockProducer { - /// "Poll" to see if the validator is required to take any action. - /// - /// The slot clock will be read and any new actions undertaken. - pub fn poll(&mut self) -> Result { - let slot = self - .slot_clock - .present_slot() - .map_err(|_| Error::SlotClockError)? - .ok_or(Error::SlotUnknowable)?; - - // If this is a new slot. - if !self.is_processed_slot(slot) { - let is_block_production_slot = match self.epoch_map.is_block_production_slot(slot) { - Ok(result) => result, - Err(DutiesReaderError::UnknownEpoch) => { - return Ok(PollOutcome::ProducerDutiesUnknown(slot)); - } - Err(DutiesReaderError::UnknownValidator) => { - return Ok(PollOutcome::ValidatorIsUnknown(slot)); - } - Err(DutiesReaderError::EpochLengthIsZero) => return Err(Error::EpochLengthIsZero), - Err(DutiesReaderError::Poisoned) => return Err(Error::EpochMapPoisoned), - }; - - if is_block_production_slot { - self.last_processed_slot = Some(slot); - - self.produce_block(slot) - } else { - Ok(PollOutcome::BlockProductionNotRequired(slot)) - } - } else { - Ok(PollOutcome::SlotAlreadyProcessed(slot)) - } - } - - fn is_processed_slot(&self, slot: Slot) -> bool { - match self.last_processed_slot { - Some(processed_slot) if processed_slot >= slot => true, - _ => false, - } - } - - /// Produce a block at some slot. - /// - /// Assumes that a block is required at this slot (does not check the duties). - /// - /// Ensures the message is not slashable. - /// - /// !!! UNSAFE !!! - /// - /// The slash-protection code is not yet implemented. There is zero protection against - /// slashing. - fn produce_block(&mut self, slot: Slot) -> Result { - let fork = match self.epoch_map.fork() { - Ok(fork) => fork, - Err(_) => return Ok(PollOutcome::UnableToGetFork(slot)), - }; - - let randao_reveal = { - // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`. - let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root(); - - match self.signer.sign_randao_reveal( - &message, - self.spec - .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork), - ) { - None => return Ok(PollOutcome::SignerRejection(slot)), - Some(signature) => signature, - } - }; - - if let Some(block) = self - .beacon_node - .produce_beacon_block(slot, &randao_reveal)? - { - if self.safe_to_produce(&block) { - let domain = self.spec.get_domain( - slot.epoch(self.spec.slots_per_epoch), - Domain::BeaconBlock, - &fork, - ); - if let Some(block) = self.sign_block(block, domain) { - self.beacon_node.publish_beacon_block(block)?; - Ok(PollOutcome::BlockProduced(slot)) - } else { - Ok(PollOutcome::SignerRejection(slot)) - } - } else { - Ok(PollOutcome::SlashableBlockNotProduced(slot)) - } - } else { - Ok(PollOutcome::BeaconNodeUnableToProduceBlock(slot)) - } - } - - /// Consumes a block, returning that block signed by the validators private key. - /// - /// Important: this function will not check to ensure the block is not slashable. This must be - /// done upstream. - fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { - self.store_produce(&block); - - match self - .signer - .sign_block_proposal(&block.signed_root()[..], domain) - { - None => None, - Some(signature) => { - block.signature = signature; - Some(block) - } - } - } - - /// Returns `true` if signing a block is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _block: &BeaconBlock) -> bool { - // TODO: ensure the producer doesn't produce slashable blocks. - // https://github.com/sigp/lighthouse/issues/160 - true - } - - /// Record that a block was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &BeaconBlock) { - // TODO: record this block production to prevent future slashings. - // https://github.com/sigp/lighthouse/issues/160 - } -} - -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) - } -} - -#[cfg(test)] -mod tests { - use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; - use super::*; - use slot_clock::TestingSlotClock; - use types::{ - test_utils::{SeedableRng, TestRandom, XorShiftRng}, - Keypair, - }; - - // TODO: implement more thorough testing. - // https://github.com/sigp/lighthouse/issues/160 - // - // These tests should serve as a good example for future tests. - - #[test] - pub fn polling() { - let mut rng = XorShiftRng::from_seed([42; 16]); - - let spec = Arc::new(ChainSpec::foundation()); - let slot_clock = Arc::new(TestingSlotClock::new(0)); - let beacon_node = Arc::new(SimulatedBeaconNode::default()); - let signer = Arc::new(LocalSigner::new(Keypair::random())); - - let mut epoch_map = EpochMap::new(spec.slots_per_epoch); - let produce_slot = Slot::new(100); - let produce_epoch = produce_slot.epoch(spec.slots_per_epoch); - epoch_map.map.insert(produce_epoch, produce_slot); - let epoch_map = Arc::new(epoch_map); - - let mut block_proposer = BlockProducer::new( - spec.clone(), - epoch_map.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - // Configure responses from the BeaconNode. - beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); - beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock)); - - // One slot before production slot... - slot_clock.set_slot(produce_slot.as_u64() - 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) - ); - - // On the produce slot... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProduced(produce_slot.into())) - ); - - // Trying the same produce slot again... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) - ); - - // One slot after the produce slot... - slot_clock.set_slot(produce_slot.as_u64() + 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) - ); - - // In an epoch without known duties... - let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch; - slot_clock.set_slot(slot); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot))) - ); - } -} diff --git a/eth2/block_proposer/src/test_utils/epoch_map.rs b/eth2/block_proposer/src/test_utils/epoch_map.rs deleted file mode 100644 index c06c376c6..000000000 --- a/eth2/block_proposer/src/test_utils/epoch_map.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::{DutiesReader, DutiesReaderError}; -use std::collections::HashMap; -use types::{Epoch, Fork, Slot}; - -pub struct EpochMap { - slots_per_epoch: u64, - pub map: HashMap, -} - -impl EpochMap { - pub fn new(slots_per_epoch: u64) -> Self { - Self { - slots_per_epoch, - map: HashMap::new(), - } - } -} - -impl DutiesReader for EpochMap { - fn is_block_production_slot(&self, slot: Slot) -> Result { - let epoch = slot.epoch(self.slots_per_epoch); - match self.map.get(&epoch) { - Some(s) if *s == slot => Ok(true), - Some(s) if *s != slot => Ok(false), - _ => Err(DutiesReaderError::UnknownEpoch), - } - } - - fn fork(&self) -> Result { - Ok(Fork { - previous_version: [0; 4], - current_version: [0; 4], - epoch: Epoch::new(0), - }) - } -} diff --git a/eth2/block_proposer/src/test_utils/local_signer.rs b/eth2/block_proposer/src/test_utils/local_signer.rs deleted file mode 100644 index d7f490c30..000000000 --- a/eth2/block_proposer/src/test_utils/local_signer.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::traits::Signer; -use std::sync::RwLock; -use types::{Keypair, Signature}; - -/// A test-only struct used to simulate a Beacon Node. -pub struct LocalSigner { - keypair: Keypair, - should_sign: RwLock, -} - -impl LocalSigner { - /// Produce a new LocalSigner with signing enabled by default. - pub fn new(keypair: Keypair) -> Self { - Self { - keypair, - should_sign: RwLock::new(true), - } - } - - /// If set to `false`, the service will refuse to sign all messages. Otherwise, all messages - /// will be signed. - pub fn enable_signing(&self, enabled: bool) { - *self.should_sign.write().unwrap() = enabled; - } -} - -impl Signer for LocalSigner { - fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.keypair.sk)) - } - - fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.keypair.sk)) - } -} diff --git a/eth2/block_proposer/src/test_utils/mod.rs b/eth2/block_proposer/src/test_utils/mod.rs deleted file mode 100644 index 481247dd0..000000000 --- a/eth2/block_proposer/src/test_utils/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod epoch_map; -mod local_signer; -mod simulated_beacon_node; - -pub use self::epoch_map::EpochMap; -pub use self::local_signer::LocalSigner; -pub use self::simulated_beacon_node::SimulatedBeaconNode; diff --git a/eth2/block_proposer/src/test_utils/simulated_beacon_node.rs b/eth2/block_proposer/src/test_utils/simulated_beacon_node.rs deleted file mode 100644 index c0a12c1ac..000000000 --- a/eth2/block_proposer/src/test_utils/simulated_beacon_node.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome}; -use std::sync::RwLock; -use types::{BeaconBlock, Signature, Slot}; - -type ProduceResult = Result, BeaconNodeError>; -type PublishResult = Result; - -/// A test-only struct used to simulate a Beacon Node. -#[derive(Default)] -pub struct SimulatedBeaconNode { - pub produce_input: RwLock>, - pub produce_result: RwLock>, - - pub publish_input: RwLock>, - pub publish_result: RwLock>, -} - -impl SimulatedBeaconNode { - /// Set the result to be returned when `produce_beacon_block` is called. - pub fn set_next_produce_result(&self, result: ProduceResult) { - *self.produce_result.write().unwrap() = Some(result); - } - - /// Set the result to be returned when `publish_beacon_block` is called. - pub fn set_next_publish_result(&self, result: PublishResult) { - *self.publish_result.write().unwrap() = Some(result); - } -} - -impl BeaconNode for SimulatedBeaconNode { - /// Returns the value specified by the `set_next_produce_result`. - fn produce_beacon_block(&self, slot: Slot, randao_reveal: &Signature) -> ProduceResult { - *self.produce_input.write().unwrap() = Some((slot, randao_reveal.clone())); - match *self.produce_result.read().unwrap() { - Some(ref r) => r.clone(), - None => panic!("SimulatedBeaconNode: produce_result == None"), - } - } - - /// Returns the value specified by the `set_next_publish_result`. - fn publish_beacon_block(&self, block: BeaconBlock) -> PublishResult { - *self.publish_input.write().unwrap() = Some(block); - match *self.publish_result.read().unwrap() { - Some(ref r) => r.clone(), - None => panic!("SimulatedBeaconNode: publish_result == None"), - } - } -} diff --git a/eth2/block_proposer/src/traits.rs b/eth2/block_proposer/src/traits.rs deleted file mode 100644 index 1c0da9acf..000000000 --- a/eth2/block_proposer/src/traits.rs +++ /dev/null @@ -1,50 +0,0 @@ -use types::{BeaconBlock, Fork, Signature, Slot}; - -#[derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeError { - RemoteFailure(String), - DecodeFailure, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum PublishOutcome { - ValidBlock, - InvalidBlock(String), -} - -/// Defines the methods required to produce and publish blocks on a Beacon Node. -pub trait BeaconNode: Send + Sync { - /// Request that the node produces a block. - /// - /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result, BeaconNodeError>; - - /// Request that the node publishes a block. - /// - /// Returns `true` if the publish was sucessful. - fn publish_beacon_block(&self, block: BeaconBlock) -> Result; -} - -#[derive(Debug, PartialEq, Clone)] -pub enum DutiesReaderError { - UnknownValidator, - UnknownEpoch, - EpochLengthIsZero, - Poisoned, -} - -/// Informs a validator of their duties (e.g., block production). -pub trait DutiesReader: Send + Sync { - fn is_block_production_slot(&self, slot: Slot) -> Result; - fn fork(&self) -> Result; -} - -/// Signs message using an internally-maintained private key. -pub trait Signer { - fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option; - fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option; -} diff --git a/eth2/fork_choice/src/bitwise_lmd_ghost.rs b/eth2/fork_choice/src/bitwise_lmd_ghost.rs index 8ae0251d2..0bbac6bb6 100644 --- a/eth2/fork_choice/src/bitwise_lmd_ghost.rs +++ b/eth2/fork_choice/src/bitwise_lmd_ghost.rs @@ -9,8 +9,9 @@ use db::{ }; use log::{debug, trace}; use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight}; +use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot, SlotHeight}; //TODO: Pruning - Children //TODO: Handle Syncing @@ -33,7 +34,7 @@ fn power_of_2_below(x: u64) -> u64 { } /// Stores the necessary data structures to run the optimised bitwise lmd ghost algorithm. -pub struct BitwiseLMDGhost { +pub struct BitwiseLMDGhost { /// A cache of known ancestors at given heights for a specific block. //TODO: Consider FnvHashMap cache: HashMap, Hash256>, @@ -50,9 +51,10 @@ pub struct BitwiseLMDGhost { /// State storage access. state_store: Arc>, max_known_height: SlotHeight, + _phantom: PhantomData, } -impl BitwiseLMDGhost +impl BitwiseLMDGhost where T: ClientDB + Sized, { @@ -68,6 +70,7 @@ where max_known_height: SlotHeight::new(0), block_store, state_store, + _phantom: PhantomData, } } @@ -85,7 +88,7 @@ where // build a hashmap of block_hash to weighted votes let mut latest_votes: HashMap = HashMap::new(); // gets the current weighted votes - let current_state = self + let current_state: BeaconState = self .state_store .get_deserialized(&state_root)? .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; @@ -240,7 +243,7 @@ where } } -impl ForkChoice for BitwiseLMDGhost { +impl ForkChoice for BitwiseLMDGhost { fn add_block( &mut self, block: &BeaconBlock, diff --git a/eth2/fork_choice/src/optimized_lmd_ghost.rs b/eth2/fork_choice/src/optimized_lmd_ghost.rs index ee2919e85..3f585e3c1 100644 --- a/eth2/fork_choice/src/optimized_lmd_ghost.rs +++ b/eth2/fork_choice/src/optimized_lmd_ghost.rs @@ -9,8 +9,9 @@ use db::{ use log::{debug, trace}; use std::cmp::Ordering; use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight}; +use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot, SlotHeight}; //TODO: Pruning - Children //TODO: Handle Syncing @@ -33,7 +34,7 @@ fn power_of_2_below(x: u64) -> u64 { } /// Stores the necessary data structures to run the optimised lmd ghost algorithm. -pub struct OptimizedLMDGhost { +pub struct OptimizedLMDGhost { /// A cache of known ancestors at given heights for a specific block. //TODO: Consider FnvHashMap cache: HashMap, Hash256>, @@ -50,9 +51,10 @@ pub struct OptimizedLMDGhost { /// State storage access. state_store: Arc>, max_known_height: SlotHeight, + _phantom: PhantomData, } -impl OptimizedLMDGhost +impl OptimizedLMDGhost where T: ClientDB + Sized, { @@ -68,6 +70,7 @@ where max_known_height: SlotHeight::new(0), block_store, state_store, + _phantom: PhantomData, } } @@ -85,7 +88,7 @@ where // build a hashmap of block_hash to weighted votes let mut latest_votes: HashMap = HashMap::new(); // gets the current weighted votes - let current_state = self + let current_state: BeaconState = self .state_store .get_deserialized(&state_root)? .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; @@ -211,7 +214,7 @@ where } } -impl ForkChoice for OptimizedLMDGhost { +impl ForkChoice for OptimizedLMDGhost { fn add_block( &mut self, block: &BeaconBlock, diff --git a/eth2/fork_choice/src/slow_lmd_ghost.rs b/eth2/fork_choice/src/slow_lmd_ghost.rs index 4b236cba4..c9aaa70d1 100644 --- a/eth2/fork_choice/src/slow_lmd_ghost.rs +++ b/eth2/fork_choice/src/slow_lmd_ghost.rs @@ -7,12 +7,13 @@ use db::{ }; use log::{debug, trace}; use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Hash256, Slot}; +use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot}; //TODO: Pruning and syncing -pub struct SlowLMDGhost { +pub struct SlowLMDGhost { /// The latest attestation targets as a map of validator index to block hash. //TODO: Could this be a fixed size vec latest_attestation_targets: HashMap, @@ -22,9 +23,10 @@ pub struct SlowLMDGhost { block_store: Arc>, /// State storage access. state_store: Arc>, + _phantom: PhantomData, } -impl SlowLMDGhost +impl SlowLMDGhost where T: ClientDB + Sized, { @@ -37,6 +39,7 @@ where children: HashMap::new(), block_store, state_store, + _phantom: PhantomData, } } @@ -54,7 +57,7 @@ where // build a hashmap of block_hash to weighted votes let mut latest_votes: HashMap = HashMap::new(); // gets the current weighted votes - let current_state = self + let current_state: BeaconState = self .state_store .get_deserialized(&state_root)? .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; @@ -105,7 +108,7 @@ where } } -impl ForkChoice for SlowLMDGhost { +impl ForkChoice for SlowLMDGhost { /// Process when a block is added fn add_block( &mut self, diff --git a/eth2/fork_choice/tests/tests.rs b/eth2/fork_choice/tests/tests.rs index fb530ac43..067d39da4 100644 --- a/eth2/fork_choice/tests/tests.rs +++ b/eth2/fork_choice/tests/tests.rs @@ -25,7 +25,9 @@ use std::collections::HashMap; use std::sync::Arc; use std::{fs::File, io::prelude::*, path::PathBuf}; use types::test_utils::TestingBeaconStateBuilder; -use types::{BeaconBlock, BeaconBlockBody, ChainSpec, Eth1Data, Hash256, Keypair, Slot}; +use types::{ + BeaconBlock, BeaconBlockBody, Eth1Data, EthSpec, FoundationEthSpec, Hash256, Keypair, Slot, +}; use yaml_rust::yaml; // Note: We Assume the block Id's are hex-encoded. @@ -82,7 +84,7 @@ fn test_yaml_vectors( let test_cases = load_test_cases_from_yaml(yaml_file_path); // default vars - let spec = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); let zero_hash = Hash256::zero(); let eth1_data = Eth1Data { deposit_root: zero_hash.clone(), @@ -227,23 +229,27 @@ fn setup_inital_state( // the fork choice instantiation let fork_choice: Box = match fork_choice_algo { - ForkChoiceAlgorithm::OptimizedLMDGhost => Box::new(OptimizedLMDGhost::new( - block_store.clone(), - state_store.clone(), - )), - ForkChoiceAlgorithm::BitwiseLMDGhost => Box::new(BitwiseLMDGhost::new( - block_store.clone(), - state_store.clone(), - )), + ForkChoiceAlgorithm::OptimizedLMDGhost => { + let f: OptimizedLMDGhost = + OptimizedLMDGhost::new(block_store.clone(), state_store.clone()); + Box::new(f) + } + ForkChoiceAlgorithm::BitwiseLMDGhost => { + let f: BitwiseLMDGhost = + BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); + Box::new(f) + } ForkChoiceAlgorithm::SlowLMDGhost => { - Box::new(SlowLMDGhost::new(block_store.clone(), state_store.clone())) + let f: SlowLMDGhost = + SlowLMDGhost::new(block_store.clone(), state_store.clone()); + Box::new(f) } ForkChoiceAlgorithm::LongestChain => Box::new(LongestChain::new(block_store.clone())), }; - let spec = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); - let mut state_builder = + let mut state_builder: TestingBeaconStateBuilder = TestingBeaconStateBuilder::from_single_keypair(num_validators, &Keypair::random(), &spec); state_builder.build_caches(&spec).unwrap(); let (state, _keypairs) = state_builder.build(); diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 69a1ccc0b..c5653e7f9 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -13,10 +13,11 @@ use state_processing::per_block_processing::{ verify_transfer_time_independent_only, }; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; +use std::marker::PhantomData; use types::chain_spec::Domain; use types::{ Attestation, AttestationData, AttesterSlashing, BeaconState, ChainSpec, Deposit, Epoch, - ProposerSlashing, Transfer, Validator, VoluntaryExit, + EthSpec, ProposerSlashing, Transfer, Validator, VoluntaryExit, }; #[cfg(test)] @@ -25,7 +26,7 @@ const VERIFY_DEPOSIT_PROOFS: bool = false; const VERIFY_DEPOSIT_PROOFS: bool = false; // TODO: enable this #[derive(Default)] -pub struct OperationPool { +pub struct OperationPool { /// Map from attestation ID (see below) to vectors of attestations. attestations: RwLock>>, /// Map from deposit index to deposit data. @@ -42,6 +43,7 @@ pub struct OperationPool { voluntary_exits: RwLock>, /// Set of transfers. transfers: RwLock>, + _phantom: PhantomData, } /// Serialized `AttestationData` augmented with a domain to encode the fork info. @@ -52,14 +54,22 @@ struct AttestationId(Vec); const DOMAIN_BYTES_LEN: usize = 8; impl AttestationId { - fn from_data(attestation: &AttestationData, state: &BeaconState, spec: &ChainSpec) -> Self { + fn from_data( + attestation: &AttestationData, + state: &BeaconState, + spec: &ChainSpec, + ) -> Self { let mut bytes = ssz_encode(attestation); let epoch = attestation.slot.epoch(spec.slots_per_epoch); bytes.extend_from_slice(&AttestationId::compute_domain_bytes(epoch, state, spec)); AttestationId(bytes) } - fn compute_domain_bytes(epoch: Epoch, state: &BeaconState, spec: &ChainSpec) -> Vec { + fn compute_domain_bytes( + epoch: Epoch, + state: &BeaconState, + spec: &ChainSpec, + ) -> Vec { int_to_bytes8(spec.get_domain(epoch, Domain::Attestation, &state.fork)) } @@ -75,7 +85,11 @@ impl AttestationId { /// receive for including it in a block. // TODO: this could be optimised with a map from validator index to whether that validator has // attested in each of the current and previous epochs. Currently quadractic in number of validators. -fn attestation_score(attestation: &Attestation, state: &BeaconState, spec: &ChainSpec) -> usize { +fn attestation_score( + attestation: &Attestation, + state: &BeaconState, + spec: &ChainSpec, +) -> usize { // Bitfield of validators whose attestations are new/fresh. let mut new_validators = attestation.aggregation_bitfield.clone(); @@ -113,7 +127,7 @@ pub enum DepositInsertStatus { Replaced(Box), } -impl OperationPool { +impl OperationPool { /// Create a new operation pool. pub fn new() -> Self { Self::default() @@ -123,7 +137,7 @@ impl OperationPool { pub fn insert_attestation( &self, attestation: Attestation, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), AttestationValidationError> { // Check that attestation signatures are valid. @@ -161,15 +175,11 @@ impl OperationPool { /// Total number of attestations in the pool, including attestations for the same data. pub fn num_attestations(&self) -> usize { - self.attestations - .read() - .values() - .map(|atts| atts.len()) - .sum() + self.attestations.read().values().map(Vec::len).sum() } /// Get a list of attestations for inclusion in a block. - pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { // Attestations for the current fork, which may be from the current or previous epoch. let prev_epoch = state.previous_epoch(spec); let current_epoch = state.current_epoch(spec); @@ -204,7 +214,7 @@ impl OperationPool { // TODO: we could probably prune other attestations here: // - ones that are completely covered by attestations included in the state // - maybe ones invalidated by the confirmation of one fork over another - pub fn prune_attestations(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_attestations(&self, finalized_state: &BeaconState, spec: &ChainSpec) { self.attestations.write().retain(|_, attestations| { // All the attestations in this bucket have the same data, so we only need to // check the first one. @@ -220,7 +230,7 @@ impl OperationPool { pub fn insert_deposit( &self, deposit: Deposit, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result { use DepositInsertStatus::*; @@ -245,7 +255,7 @@ impl OperationPool { /// Get an ordered list of deposits for inclusion in a block. /// /// Take at most the maximum number of deposits, beginning from the current deposit index. - pub fn get_deposits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + pub fn get_deposits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { let start_idx = state.deposit_index; (start_idx..start_idx + spec.max_deposits) .map(|idx| self.deposits.read().get(&idx).cloned()) @@ -255,7 +265,7 @@ impl OperationPool { } /// Remove all deposits with index less than the deposit index of the latest finalised block. - pub fn prune_deposits(&self, state: &BeaconState) -> BTreeMap { + pub fn prune_deposits(&self, state: &BeaconState) -> BTreeMap { let deposits_keep = self.deposits.write().split_off(&state.deposit_index); std::mem::replace(&mut self.deposits.write(), deposits_keep) } @@ -269,7 +279,7 @@ impl OperationPool { pub fn insert_proposer_slashing( &self, slashing: ProposerSlashing, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), ProposerSlashingValidationError> { // TODO: should maybe insert anyway if the proposer is unknown in the validator index, @@ -286,7 +296,7 @@ impl OperationPool { /// Depends on the fork field of the state, but not on the state's epoch. fn attester_slashing_id( slashing: &AttesterSlashing, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> (AttestationId, AttestationId) { ( @@ -299,7 +309,7 @@ impl OperationPool { pub fn insert_attester_slashing( &self, slashing: AttesterSlashing, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), AttesterSlashingValidationError> { verify_attester_slashing(state, &slashing, true, spec)?; @@ -315,7 +325,7 @@ impl OperationPool { /// earlier in the block. pub fn get_slashings( &self, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> (Vec, Vec) { let proposer_slashings = filter_limit_operations( @@ -370,7 +380,7 @@ impl OperationPool { } /// Prune proposer slashings for all slashed or withdrawn validators. - pub fn prune_proposer_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_proposer_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { prune_validator_hash_map( &mut self.proposer_slashings.write(), |validator| { @@ -383,7 +393,7 @@ impl OperationPool { /// Prune attester slashings for all slashed or withdrawn validators, or attestations on another /// fork. - pub fn prune_attester_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_attester_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { self.attester_slashings.write().retain(|id, slashing| { let fork_ok = &Self::attester_slashing_id(slashing, finalized_state, spec) == id; let curr_epoch = finalized_state.current_epoch(spec); @@ -402,7 +412,7 @@ impl OperationPool { pub fn insert_voluntary_exit( &self, exit: VoluntaryExit, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), ExitValidationError> { verify_exit_time_independent_only(state, &exit, spec)?; @@ -413,7 +423,11 @@ impl OperationPool { } /// Get a list of voluntary exits for inclusion in a block. - pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + pub fn get_voluntary_exits( + &self, + state: &BeaconState, + spec: &ChainSpec, + ) -> Vec { filter_limit_operations( self.voluntary_exits.read().values(), |exit| verify_exit(state, exit, spec).is_ok(), @@ -422,7 +436,7 @@ impl OperationPool { } /// Prune if validator has already exited at the last finalized state. - pub fn prune_voluntary_exits(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_voluntary_exits(&self, finalized_state: &BeaconState, spec: &ChainSpec) { prune_validator_hash_map( &mut self.voluntary_exits.write(), |validator| validator.is_exited_at(finalized_state.current_epoch(spec)), @@ -434,7 +448,7 @@ impl OperationPool { pub fn insert_transfer( &self, transfer: Transfer, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), TransferValidationError> { // The signature of the transfer isn't hashed, but because we check @@ -448,7 +462,7 @@ impl OperationPool { /// Get a list of transfers for inclusion in a block. // TODO: improve the economic optimality of this function by accounting for // dependencies between transfers in the same block e.g. A pays B, B pays C - pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { self.transfers .read() .iter() @@ -460,14 +474,14 @@ impl OperationPool { } /// Prune the set of transfers by removing all those whose slot has already passed. - pub fn prune_transfers(&self, finalized_state: &BeaconState) { + pub fn prune_transfers(&self, finalized_state: &BeaconState) { self.transfers .write() .retain(|transfer| transfer.slot > finalized_state.slot) } /// Prune all types of transactions given the latest finalized state. - pub fn prune_all(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_all(&self, finalized_state: &BeaconState, spec: &ChainSpec) { self.prune_attestations(finalized_state, spec); self.prune_deposits(finalized_state); self.prune_proposer_slashings(finalized_state, spec); @@ -487,7 +501,10 @@ impl OperationPool { /// /// - Their `AttestationData` is equal. /// - `attestation` does not contain any signatures that `PendingAttestation` does not have. -fn superior_attestation_exists_in_state(state: &BeaconState, attestation: &Attestation) -> bool { +fn superior_attestation_exists_in_state( + state: &BeaconState, + attestation: &Attestation, +) -> bool { state .current_epoch_attestations .iter() @@ -522,10 +539,10 @@ where /// The keys in the map should be validator indices, which will be looked up /// in the state's validator registry and then passed to `prune_if`. /// Entries for unknown validators will be kept. -fn prune_validator_hash_map( +fn prune_validator_hash_map( map: &mut HashMap, prune_if: F, - finalized_state: &BeaconState, + finalized_state: &BeaconState, ) where F: Fn(&Validator) -> bool, { @@ -649,7 +666,11 @@ mod tests { } // Create a random deposit (with a valid proof of posession) - fn make_deposit(rng: &mut XorShiftRng, state: &BeaconState, spec: &ChainSpec) -> Deposit { + fn make_deposit( + rng: &mut XorShiftRng, + state: &BeaconState, + spec: &ChainSpec, + ) -> Deposit { let keypair = Keypair::random(); let mut deposit = Deposit::random_for_test(rng); let mut deposit_input = DepositInput { @@ -668,9 +689,9 @@ mod tests { } // Create `count` dummy deposits with sequential deposit IDs beginning from `start`. - fn dummy_deposits( + fn dummy_deposits( rng: &mut XorShiftRng, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, start: u64, count: u64, @@ -685,301 +706,315 @@ mod tests { .collect() } - fn test_state(rng: &mut XorShiftRng) -> (ChainSpec, BeaconState) { - let spec = ChainSpec::foundation(); + fn test_state(rng: &mut XorShiftRng) -> (ChainSpec, BeaconState) { + let spec = FoundationEthSpec::spec(); + let mut state = BeaconState::random_for_test(rng); + state.fork = Fork::genesis(&spec); (spec, state) } - /// Create a signed attestation for use in tests. - /// Signed by all validators in `committee[signing_range]` and `committee[extra_signer]`. #[cfg(not(debug_assertions))] - fn signed_attestation>( - committee: &CrosslinkCommittee, - keypairs: &[Keypair], - signing_range: R, - slot: Slot, - state: &BeaconState, - spec: &ChainSpec, - extra_signer: Option, - ) -> Attestation { - let mut builder = TestingAttestationBuilder::new( - state, - &committee.committee, - slot, - committee.shard, - spec, - ); - let signers = &committee.committee[signing_range]; - let committee_keys = signers.iter().map(|&i| &keypairs[i].sk).collect::>(); - builder.sign(signers, &committee_keys, &state.fork, spec); - extra_signer.map(|c_idx| { - let validator_index = committee.committee[c_idx]; - builder.sign( - &[validator_index], - &[&keypairs[validator_index].sk], - &state.fork, + mod release_tests { + use super::*; + + /// Create a signed attestation for use in tests. + /// Signed by all validators in `committee[signing_range]` and `committee[extra_signer]`. + fn signed_attestation, E: EthSpec>( + committee: &CrosslinkCommittee, + keypairs: &[Keypair], + signing_range: R, + slot: Slot, + state: &BeaconState, + spec: &ChainSpec, + extra_signer: Option, + ) -> Attestation { + let mut builder = TestingAttestationBuilder::new( + state, + &committee.committee, + slot, + committee.shard, spec, - ) - }); - builder.build() - } - - /// Test state for attestation-related tests. - #[cfg(not(debug_assertions))] - fn attestation_test_state( - spec: &ChainSpec, - num_committees: usize, - ) -> (BeaconState, Vec) { - let num_validators = - num_committees * (spec.slots_per_epoch * spec.target_committee_size) as usize; - let mut state_builder = - TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, spec); - let slot_offset = 1000 * spec.slots_per_epoch + spec.slots_per_epoch / 2; - let slot = spec.genesis_slot + slot_offset; - state_builder.teleport_to_slot(slot, spec); - state_builder.build_caches(spec).unwrap(); - state_builder.build() - } - - /// Set the latest crosslink in the state to match the attestation. - #[cfg(not(debug_assertions))] - fn fake_latest_crosslink(att: &Attestation, state: &mut BeaconState, spec: &ChainSpec) { - state.latest_crosslinks[att.data.shard as usize] = Crosslink { - crosslink_data_root: att.data.crosslink_data_root, - epoch: att.data.slot.epoch(spec.slots_per_epoch), - }; - } - - #[test] - #[cfg(not(debug_assertions))] - fn test_attestation_score() { - let spec = &ChainSpec::foundation(); - let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let slot = state.slot - 1; - let committees = state - .get_crosslink_committees_at_slot(slot, spec) - .unwrap() - .clone(); - - for committee in committees { - let att1 = signed_attestation(&committee, keypairs, ..2, slot, state, spec, None); - let att2 = signed_attestation(&committee, keypairs, .., slot, state, spec, None); - - assert_eq!( - att1.aggregation_bitfield.num_set_bits(), - attestation_score(&att1, state, spec) - ); - - state - .current_epoch_attestations - .push(PendingAttestation::from_attestation(&att1, state.slot)); - - assert_eq!( - committee.committee.len() - 2, - attestation_score(&att2, state, spec) ); + let signers = &committee.committee[signing_range]; + let committee_keys = signers.iter().map(|&i| &keypairs[i].sk).collect::>(); + builder.sign(signers, &committee_keys, &state.fork, spec); + extra_signer.map(|c_idx| { + let validator_index = committee.committee[c_idx]; + builder.sign( + &[validator_index], + &[&keypairs[validator_index].sk], + &state.fork, + spec, + ) + }); + builder.build() } - } - /// End-to-end test of basic attestation handling. - #[test] - #[cfg(not(debug_assertions))] - fn attestation_aggregation_insert_get_prune() { - let spec = &ChainSpec::foundation(); - let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let op_pool = OperationPool::new(); + /// Test state for attestation-related tests. + fn attestation_test_state( + num_committees: usize, + ) -> (BeaconState, Vec, ChainSpec) { + let spec = E::spec(); - let slot = state.slot - 1; - let committees = state - .get_crosslink_committees_at_slot(slot, spec) - .unwrap() - .clone(); + let num_validators = + num_committees * (spec.slots_per_epoch * spec.target_committee_size) as usize; + let mut state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists( + num_validators, + &spec, + ); + let slot_offset = 1000 * spec.slots_per_epoch + spec.slots_per_epoch / 2; + let slot = spec.genesis_slot + slot_offset; + state_builder.teleport_to_slot(slot, &spec); + state_builder.build_caches(&spec).unwrap(); + let (state, keypairs) = state_builder.build(); - assert_eq!( - committees.len(), - 1, - "we expect just one committee with this many validators" - ); + (state, keypairs, FoundationEthSpec::spec()) + } + + /// Set the latest crosslink in the state to match the attestation. + fn fake_latest_crosslink( + att: &Attestation, + state: &mut BeaconState, + spec: &ChainSpec, + ) { + state.latest_crosslinks[att.data.shard as usize] = Crosslink { + crosslink_data_root: att.data.crosslink_data_root, + epoch: att.data.slot.epoch(spec.slots_per_epoch), + }; + } + + #[test] + fn test_attestation_score() { + let (ref mut state, ref keypairs, ref spec) = + attestation_test_state::(1); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + for committee in committees { + let att1 = signed_attestation(&committee, keypairs, ..2, slot, state, spec, None); + let att2 = signed_attestation(&committee, keypairs, .., slot, state, spec, None); + + assert_eq!( + att1.aggregation_bitfield.num_set_bits(), + attestation_score(&att1, state, spec) + ); + + state + .current_epoch_attestations + .push(PendingAttestation::from_attestation(&att1, state.slot)); + + assert_eq!( + committee.committee.len() - 2, + attestation_score(&att2, state, spec) + ); + } + } + + /// End-to-end test of basic attestation handling. + #[test] + fn attestation_aggregation_insert_get_prune() { + let (ref mut state, ref keypairs, ref spec) = + attestation_test_state::(1); + + let op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + assert_eq!( + committees.len(), + 1, + "we expect just one committee with this many validators" + ); + + for committee in &committees { + let step_size = 2; + for i in (0..committee.committee.len()).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + step_size, + slot, + state, + spec, + None, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + } + + assert_eq!(op_pool.attestations.read().len(), committees.len()); + assert_eq!(op_pool.num_attestations(), committees.len()); + + // Before the min attestation inclusion delay, get_attestations shouldn't return anything. + assert_eq!(op_pool.get_attestations(state, spec).len(), 0); + + // Then once the delay has elapsed, we should get a single aggregated attestation. + state.slot += spec.min_attestation_inclusion_delay; + + let block_attestations = op_pool.get_attestations(state, spec); + assert_eq!(block_attestations.len(), committees.len()); + + let agg_att = &block_attestations[0]; + assert_eq!( + agg_att.aggregation_bitfield.num_set_bits(), + spec.target_committee_size as usize + ); + + // Prune attestations shouldn't do anything at this point. + op_pool.prune_attestations(state, spec); + assert_eq!(op_pool.num_attestations(), committees.len()); + + // But once we advance to an epoch after the attestation, it should prune it out of + // existence. + state.slot = slot + spec.slots_per_epoch; + op_pool.prune_attestations(state, spec); + assert_eq!(op_pool.num_attestations(), 0); + } + + /// Adding an attestation already in the pool should not increase the size of the pool. + #[test] + fn attestation_duplicate() { + let (ref mut state, ref keypairs, ref spec) = + attestation_test_state::(1); + + let op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + for committee in &committees { + let att = signed_attestation(committee, keypairs, .., slot, state, spec, None); + fake_latest_crosslink(&att, state, spec); + op_pool + .insert_attestation(att.clone(), state, spec) + .unwrap(); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + + assert_eq!(op_pool.num_attestations(), committees.len()); + } + + /// Adding lots of attestations that only intersect pairwise should lead to two aggregate + /// attestations. + #[test] + fn attestation_pairwise_overlapping() { + let (ref mut state, ref keypairs, ref spec) = + attestation_test_state::(1); + + let op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); - for committee in &committees { let step_size = 2; - for i in (0..committee.committee.len()).step_by(step_size) { - let att = signed_attestation( - committee, - keypairs, - i..i + step_size, - slot, - state, - spec, - None, - ); - fake_latest_crosslink(&att, state, spec); - op_pool.insert_attestation(att, state, spec).unwrap(); + for committee in &committees { + // Create attestations that overlap on `step_size` validators, like: + // {0,1,2,3}, {2,3,4,5}, {4,5,6,7}, ... + for i in (0..committee.committee.len() - step_size).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + 2 * step_size, + slot, + state, + spec, + None, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } } + + // The attestations should get aggregated into two attestations that comprise all + // validators. + assert_eq!(op_pool.attestations.read().len(), committees.len()); + assert_eq!(op_pool.num_attestations(), 2 * committees.len()); } - assert_eq!(op_pool.attestations.read().len(), committees.len()); - assert_eq!(op_pool.num_attestations(), committees.len()); + /// Create a bunch of attestations signed by a small number of validators, and another + /// bunch signed by a larger number, such that there are at least `max_attestations` + /// signed by the larger number. Then, check that `get_attestations` only returns the + /// high-quality attestations. To ensure that no aggregation occurs, ALL attestations + /// are also signed by the 0th member of the committee. + #[test] + fn attestation_get_max() { + let small_step_size = 2; + let big_step_size = 4; - // Before the min attestation inclusion delay, get_attestations shouldn't return anything. - assert_eq!(op_pool.get_attestations(state, spec).len(), 0); + let (ref mut state, ref keypairs, ref spec) = + attestation_test_state::(big_step_size); - // Then once the delay has elapsed, we should get a single aggregated attestation. - state.slot += spec.min_attestation_inclusion_delay; + let op_pool = OperationPool::new(); - let block_attestations = op_pool.get_attestations(state, spec); - assert_eq!(block_attestations.len(), committees.len()); + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); - let agg_att = &block_attestations[0]; - assert_eq!( - agg_att.aggregation_bitfield.num_set_bits(), - spec.target_committee_size as usize - ); + let max_attestations = spec.max_attestations as usize; + let target_committee_size = spec.target_committee_size as usize; - // Prune attestations shouldn't do anything at this point. - op_pool.prune_attestations(state, spec); - assert_eq!(op_pool.num_attestations(), committees.len()); + let mut insert_attestations = |committee, step_size| { + for i in (0..target_committee_size).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + step_size, + slot, + state, + spec, + if i == 0 { None } else { Some(0) }, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + }; - // But once we advance to an epoch after the attestation, it should prune it out of - // existence. - state.slot = slot + spec.slots_per_epoch; - op_pool.prune_attestations(state, spec); - assert_eq!(op_pool.num_attestations(), 0); - } - - /// Adding an attestation already in the pool should not increase the size of the pool. - #[test] - #[cfg(not(debug_assertions))] - fn attestation_duplicate() { - let spec = &ChainSpec::foundation(); - let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let op_pool = OperationPool::new(); - - let slot = state.slot - 1; - let committees = state - .get_crosslink_committees_at_slot(slot, spec) - .unwrap() - .clone(); - - for committee in &committees { - let att = signed_attestation(committee, keypairs, .., slot, state, spec, None); - fake_latest_crosslink(&att, state, spec); - op_pool - .insert_attestation(att.clone(), state, spec) - .unwrap(); - op_pool.insert_attestation(att, state, spec).unwrap(); - } - - assert_eq!(op_pool.num_attestations(), committees.len()); - } - - /// Adding lots of attestations that only intersect pairwise should lead to two aggregate - /// attestations. - #[test] - #[cfg(not(debug_assertions))] - fn attestation_pairwise_overlapping() { - let spec = &ChainSpec::foundation(); - let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let op_pool = OperationPool::new(); - - let slot = state.slot - 1; - let committees = state - .get_crosslink_committees_at_slot(slot, spec) - .unwrap() - .clone(); - - let step_size = 2; - for committee in &committees { - // Create attestations that overlap on `step_size` validators, like: - // {0,1,2,3}, {2,3,4,5}, {4,5,6,7}, ... - for i in (0..committee.committee.len() - step_size).step_by(step_size) { - let att = signed_attestation( - committee, - keypairs, - i..i + 2 * step_size, - slot, - state, - spec, - None, - ); - fake_latest_crosslink(&att, state, spec); - op_pool.insert_attestation(att, state, spec).unwrap(); + for committee in &committees { + assert_eq!(committee.committee.len(), target_committee_size); + // Attestations signed by only 2-3 validators + insert_attestations(committee, small_step_size); + // Attestations signed by 4+ validators + insert_attestations(committee, big_step_size); } - } - // The attestations should get aggregated into two attestations that comprise all - // validators. - assert_eq!(op_pool.attestations.read().len(), committees.len()); - assert_eq!(op_pool.num_attestations(), 2 * committees.len()); - } + let num_small = target_committee_size / small_step_size; + let num_big = target_committee_size / big_step_size; - /// Create a bunch of attestations signed by a small number of validators, and another - /// bunch signed by a larger number, such that there are at least `max_attestations` - /// signed by the larger number. Then, check that `get_attestations` only returns the - /// high-quality attestations. To ensure that no aggregation occurs, ALL attestations - /// are also signed by the 0th member of the committee. - #[test] - #[cfg(not(debug_assertions))] - fn attestation_get_max() { - let spec = &ChainSpec::foundation(); - let small_step_size = 2; - let big_step_size = 4; - let (ref mut state, ref keypairs) = attestation_test_state(spec, big_step_size); - let op_pool = OperationPool::new(); + assert_eq!(op_pool.attestations.read().len(), committees.len()); + assert_eq!( + op_pool.num_attestations(), + (num_small + num_big) * committees.len() + ); + assert!(op_pool.num_attestations() > max_attestations); - let slot = state.slot - 1; - let committees = state - .get_crosslink_committees_at_slot(slot, spec) - .unwrap() - .clone(); + state.slot += spec.min_attestation_inclusion_delay; + let best_attestations = op_pool.get_attestations(state, spec); + assert_eq!(best_attestations.len(), max_attestations); - let max_attestations = spec.max_attestations as usize; - let target_committee_size = spec.target_committee_size as usize; - - let mut insert_attestations = |committee, step_size| { - for i in (0..target_committee_size).step_by(step_size) { - let att = signed_attestation( - committee, - keypairs, - i..i + step_size, - slot, - state, - spec, - if i == 0 { None } else { Some(0) }, - ); - fake_latest_crosslink(&att, state, spec); - op_pool.insert_attestation(att, state, spec).unwrap(); + // All the best attestations should be signed by at least `big_step_size` (4) validators. + for att in &best_attestations { + assert!(att.aggregation_bitfield.num_set_bits() >= big_step_size); } - }; - - for committee in &committees { - assert_eq!(committee.committee.len(), target_committee_size); - // Attestations signed by only 2-3 validators - insert_attestations(committee, small_step_size); - // Attestations signed by 4+ validators - insert_attestations(committee, big_step_size); - } - - let num_small = target_committee_size / small_step_size; - let num_big = target_committee_size / big_step_size; - - assert_eq!(op_pool.attestations.read().len(), committees.len()); - assert_eq!( - op_pool.num_attestations(), - (num_small + num_big) * committees.len() - ); - assert!(op_pool.num_attestations() > max_attestations); - - state.slot += spec.min_attestation_inclusion_delay; - let best_attestations = op_pool.get_attestations(state, spec); - assert_eq!(best_attestations.len(), max_attestations); - - // All the best attestations should be signed by at least `big_step_size` (4) validators. - for att in &best_attestations { - assert!(att.aggregation_bitfield.num_set_bits() >= big_step_size); } } diff --git a/eth2/state_processing/Cargo.toml b/eth2/state_processing/Cargo.toml index 62722aac8..4b031022a 100644 --- a/eth2/state_processing/Cargo.toml +++ b/eth2/state_processing/Cargo.toml @@ -14,7 +14,6 @@ env_logger = "0.6.0" serde = "1.0" serde_derive = "1.0" serde_yaml = "0.8" -yaml-utils = { path = "yaml_utils" } [dependencies] bls = { path = "../utils/bls" } @@ -26,5 +25,7 @@ log = "0.4" merkle_proof = { path = "../utils/merkle_proof" } ssz = { path = "../utils/ssz" } ssz_derive = { path = "../utils/ssz_derive" } +tree_hash = { path = "../utils/tree_hash" } +tree_hash_derive = { path = "../utils/tree_hash_derive" } types = { path = "../types" } rayon = "1.0" diff --git a/eth2/state_processing/benches/bench_block_processing.rs b/eth2/state_processing/benches/bench_block_processing.rs index 2ee08c96a..80be1828f 100644 --- a/eth2/state_processing/benches/bench_block_processing.rs +++ b/eth2/state_processing/benches/bench_block_processing.rs @@ -1,6 +1,5 @@ use criterion::Criterion; use criterion::{black_box, Benchmark}; -use ssz::TreeHash; use state_processing::{ per_block_processing, per_block_processing::{ @@ -9,6 +8,7 @@ use state_processing::{ verify_block_signature, }, }; +use tree_hash::TreeHash; use types::*; /// Run the detailed benchmarking suite on the given `BeaconState`. @@ -263,7 +263,7 @@ pub fn bench_block_processing( c.bench( &format!("{}/block_processing", desc), Benchmark::new("tree_hash_block", move |b| { - b.iter(|| black_box(block.hash_tree_root())) + b.iter(|| black_box(block.tree_hash_root())) }) .sample_size(10), ); diff --git a/eth2/state_processing/benches/bench_epoch_processing.rs b/eth2/state_processing/benches/bench_epoch_processing.rs index cc7701296..9bff3a2e3 100644 --- a/eth2/state_processing/benches/bench_epoch_processing.rs +++ b/eth2/state_processing/benches/bench_epoch_processing.rs @@ -1,6 +1,5 @@ use criterion::Criterion; use criterion::{black_box, Benchmark}; -use ssz::TreeHash; use state_processing::{ per_epoch_processing, per_epoch_processing::{ @@ -9,6 +8,7 @@ use state_processing::{ update_active_tree_index_roots, update_latest_slashed_balances, }, }; +use tree_hash::TreeHash; use types::test_utils::TestingBeaconStateBuilder; use types::*; @@ -256,7 +256,7 @@ fn bench_epoch_processing(c: &mut Criterion, state: &BeaconState, spec: &ChainSp c.bench( &format!("{}/epoch_processing", desc), Benchmark::new("tree_hash_state", move |b| { - b.iter(|| black_box(state_clone.hash_tree_root())) + b.iter(|| black_box(state_clone.tree_hash_root())) }) .sample_size(SMALL_BENCHING_SAMPLE_SIZE), ); diff --git a/eth2/state_processing/src/common/exit_validator.rs b/eth2/state_processing/src/common/exit_validator.rs index 8ab530b18..529f5e161 100644 --- a/eth2/state_processing/src/common/exit_validator.rs +++ b/eth2/state_processing/src/common/exit_validator.rs @@ -2,9 +2,9 @@ use types::{BeaconStateError as Error, *}; /// Exit the validator of the given `index`. /// -/// Spec v0.5.0 -pub fn exit_validator( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn exit_validator( + state: &mut BeaconState, validator_index: usize, spec: &ChainSpec, ) -> Result<(), Error> { diff --git a/eth2/state_processing/src/common/slash_validator.rs b/eth2/state_processing/src/common/slash_validator.rs index 9be87b978..63c1e89ad 100644 --- a/eth2/state_processing/src/common/slash_validator.rs +++ b/eth2/state_processing/src/common/slash_validator.rs @@ -3,9 +3,9 @@ use types::{BeaconStateError as Error, *}; /// Slash the validator with index ``index``. /// -/// Spec v0.5.0 -pub fn slash_validator( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn slash_validator( + state: &mut BeaconState, validator_index: usize, spec: &ChainSpec, ) -> Result<(), Error> { @@ -36,8 +36,7 @@ pub fn slash_validator( state.set_slashed_balance( current_epoch, - state.get_slashed_balance(current_epoch, spec)? + effective_balance, - spec, + state.get_slashed_balance(current_epoch)? + effective_balance, )?; let whistleblower_index = @@ -56,7 +55,7 @@ pub fn slash_validator( state.validator_registry[validator_index].slashed = true; state.validator_registry[validator_index].withdrawable_epoch = - current_epoch + Epoch::from(spec.latest_slashed_exit_length); + current_epoch + Epoch::from(T::LatestSlashedExitLength::to_usize()); Ok(()) } diff --git a/eth2/state_processing/src/common/verify_bitfield.rs b/eth2/state_processing/src/common/verify_bitfield.rs index 03fcdbb67..570a240f1 100644 --- a/eth2/state_processing/src/common/verify_bitfield.rs +++ b/eth2/state_processing/src/common/verify_bitfield.rs @@ -4,7 +4,7 @@ use types::*; /// /// Is title `verify_bitfield` in spec. /// -/// Spec v0.5.0 +/// Spec v0.5.1 pub fn verify_bitfield_length(bitfield: &Bitfield, committee_size: usize) -> bool { if bitfield.num_bytes() != ((committee_size + 7) / 8) { return false; @@ -18,3 +18,62 @@ pub fn verify_bitfield_length(bitfield: &Bitfield, committee_size: usize) -> boo true } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn bitfield_length() { + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b0000_0001]), 4), + true + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b0001_0001]), 4), + false + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b0000_0000]), 4), + true + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b1000_0000]), 8), + true + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b1000_0000, 0b0000_0000]), 16), + true + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b1000_0000, 0b0000_0000]), 15), + false + ); + + assert_eq!( + verify_bitfield_length(&Bitfield::from_bytes(&[0b0000_0000, 0b0000_0000]), 8), + false + ); + + assert_eq!( + verify_bitfield_length( + &Bitfield::from_bytes(&[0b0000_0000, 0b0000_0000, 0b0000_0000]), + 8 + ), + false + ); + + assert_eq!( + verify_bitfield_length( + &Bitfield::from_bytes(&[0b0000_0000, 0b0000_0000, 0b0000_0000]), + 24 + ), + true + ); + } +} diff --git a/eth2/state_processing/src/get_genesis_state.rs b/eth2/state_processing/src/get_genesis_state.rs index 7c4d4cafd..6638b5246 100644 --- a/eth2/state_processing/src/get_genesis_state.rs +++ b/eth2/state_processing/src/get_genesis_state.rs @@ -1,5 +1,5 @@ use super::per_block_processing::{errors::BlockProcessingError, process_deposits}; -use ssz::TreeHash; +use tree_hash::TreeHash; use types::*; pub enum GenesisError { @@ -9,13 +9,13 @@ pub enum GenesisError { /// Returns the genesis `BeaconState` /// -/// Spec v0.5.0 -pub fn get_genesis_state( +/// Spec v0.5.1 +pub fn get_genesis_state( genesis_validator_deposits: &[Deposit], genesis_time: u64, genesis_eth1_data: Eth1Data, spec: &ChainSpec, -) -> Result<(), BlockProcessingError> { +) -> Result, BlockProcessingError> { // Get the genesis `BeaconState` let mut state = BeaconState::genesis(genesis_time, genesis_eth1_data, spec); @@ -36,13 +36,13 @@ pub fn get_genesis_state( let active_validator_indices = state .get_cached_active_validator_indices(RelativeEpoch::Current, spec)? .to_vec(); - let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.hash_tree_root()); - state.fill_active_index_roots_with(genesis_active_index_root, spec); + let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.tree_hash_root()); + state.fill_active_index_roots_with(genesis_active_index_root); // Generate the current shuffling seed. state.current_shuffling_seed = state.generate_seed(spec.genesis_epoch, spec)?; - Ok(()) + Ok(state) } impl From for GenesisError { diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index ac874d95e..251d7cd91 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -1,7 +1,7 @@ use crate::common::slash_validator; use errors::{BlockInvalid as Invalid, BlockProcessingError as Error, IntoWithIndex}; use rayon::prelude::*; -use ssz::{SignedRoot, TreeHash}; +use tree_hash::{SignedRoot, TreeHash}; use types::*; pub use self::verify_attester_slashing::{ @@ -41,9 +41,9 @@ const VERIFY_DEPOSIT_MERKLE_PROOFS: bool = false; /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise /// returns an error describing why the block was invalid or how the function failed to execute. /// -/// Spec v0.5.0 -pub fn per_block_processing( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn per_block_processing( + state: &mut BeaconState, block: &BeaconBlock, spec: &ChainSpec, ) -> Result<(), Error> { @@ -56,9 +56,9 @@ pub fn per_block_processing( /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise /// returns an error describing why the block was invalid or how the function failed to execute. /// -/// Spec v0.5.0 -pub fn per_block_processing_without_verifying_block_signature( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn per_block_processing_without_verifying_block_signature( + state: &mut BeaconState, block: &BeaconBlock, spec: &ChainSpec, ) -> Result<(), Error> { @@ -71,9 +71,9 @@ pub fn per_block_processing_without_verifying_block_signature( /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise /// returns an error describing why the block was invalid or how the function failed to execute. /// -/// Spec v0.5.0 -fn per_block_processing_signature_optional( - mut state: &mut BeaconState, +/// Spec v0.5.1 +fn per_block_processing_signature_optional( + mut state: &mut BeaconState, block: &BeaconBlock, should_verify_block_signature: bool, spec: &ChainSpec, @@ -101,20 +101,22 @@ fn per_block_processing_signature_optional( /// Processes the block header. /// -/// Spec v0.5.0 -pub fn process_block_header( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_block_header( + state: &mut BeaconState, block: &BeaconBlock, spec: &ChainSpec, ) -> Result<(), Error> { verify!(block.slot == state.slot, Invalid::StateSlotMismatch); - // NOTE: this is not to spec. I think spec is broken. See: - // - // https://github.com/ethereum/eth2.0-specs/issues/797 + let expected_previous_block_root = + Hash256::from_slice(&state.latest_block_header.signed_root()); verify!( - block.previous_block_root == *state.get_block_root(state.slot - 1, spec)?, - Invalid::ParentBlockRootMismatch + block.previous_block_root == expected_previous_block_root, + Invalid::ParentBlockRootMismatch { + state: expected_previous_block_root, + block: block.previous_block_root, + } ); state.latest_block_header = block.temporary_block_header(spec); @@ -124,9 +126,9 @@ pub fn process_block_header( /// Verifies the signature of a block. /// -/// Spec v0.5.0 -pub fn verify_block_signature( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_block_signature( + state: &BeaconState, block: &BeaconBlock, spec: &ChainSpec, ) -> Result<(), Error> { @@ -152,9 +154,9 @@ pub fn verify_block_signature( /// Verifies the `randao_reveal` against the block's proposer pubkey and updates /// `state.latest_randao_mixes`. /// -/// Spec v0.5.0 -pub fn process_randao( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_randao( + state: &mut BeaconState, block: &BeaconBlock, spec: &ChainSpec, ) -> Result<(), Error> { @@ -164,7 +166,7 @@ pub fn process_randao( // Verify the RANDAO is a valid signature of the proposer. verify!( block.body.randao_reveal.verify( - &state.current_epoch(spec).hash_tree_root()[..], + &state.current_epoch(spec).tree_hash_root()[..], spec.get_domain( block.slot.epoch(spec.slots_per_epoch), Domain::Randao, @@ -183,8 +185,11 @@ pub fn process_randao( /// Update the `state.eth1_data_votes` based upon the `eth1_data` provided. /// -/// Spec v0.5.0 -pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Result<(), Error> { +/// Spec v0.5.1 +pub fn process_eth1_data( + state: &mut BeaconState, + eth1_data: &Eth1Data, +) -> Result<(), Error> { // Attempt to find a `Eth1DataVote` with matching `Eth1Data`. let matching_eth1_vote_index = state .eth1_data_votes @@ -209,9 +214,9 @@ pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Resul /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_proposer_slashings( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_proposer_slashings( + state: &mut BeaconState, proposer_slashings: &[ProposerSlashing], spec: &ChainSpec, ) -> Result<(), Error> { @@ -242,9 +247,9 @@ pub fn process_proposer_slashings( /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_attester_slashings( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_attester_slashings( + state: &mut BeaconState, attester_slashings: &[AttesterSlashing], spec: &ChainSpec, ) -> Result<(), Error> { @@ -300,9 +305,9 @@ pub fn process_attester_slashings( /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_attestations( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_attestations( + state: &mut BeaconState, attestations: &[Attestation], spec: &ChainSpec, ) -> Result<(), Error> { @@ -342,9 +347,9 @@ pub fn process_attestations( /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_deposits( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_deposits( + state: &mut BeaconState, deposits: &[Deposit], spec: &ChainSpec, ) -> Result<(), Error> { @@ -412,9 +417,9 @@ pub fn process_deposits( /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_exits( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_exits( + state: &mut BeaconState, voluntary_exits: &[VoluntaryExit], spec: &ChainSpec, ) -> Result<(), Error> { @@ -444,9 +449,9 @@ pub fn process_exits( /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// an `Err` describing the invalid object or cause of failure. /// -/// Spec v0.5.0 -pub fn process_transfers( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_transfers( + state: &mut BeaconState, transfers: &[Transfer], spec: &ChainSpec, ) -> Result<(), Error> { diff --git a/eth2/state_processing/src/per_block_processing/errors.rs b/eth2/state_processing/src/per_block_processing/errors.rs index 6614f6f60..d8627d359 100644 --- a/eth2/state_processing/src/per_block_processing/errors.rs +++ b/eth2/state_processing/src/per_block_processing/errors.rs @@ -67,7 +67,10 @@ impl_from_beacon_state_error!(BlockProcessingError); #[derive(Debug, PartialEq)] pub enum BlockInvalid { StateSlotMismatch, - ParentBlockRootMismatch, + ParentBlockRootMismatch { + state: Hash256, + block: Hash256, + }, BadSignature, BadRandaoSignature, MaxAttestationsExceeded, @@ -271,10 +274,10 @@ pub enum ProposerSlashingValidationError { pub enum ProposerSlashingInvalid { /// The proposer index is not a known validator. ProposerUnknown(u64), - /// The two proposal have different slots. + /// The two proposal have different epochs. /// /// (proposal_1_slot, proposal_2_slot) - ProposalSlotMismatch(Slot, Slot), + ProposalEpochMismatch(Slot, Slot), /// The proposals are identical and therefore not slashable. ProposalsIdentical, /// The specified proposer has already been slashed. diff --git a/eth2/state_processing/src/per_block_processing/validate_attestation.rs b/eth2/state_processing/src/per_block_processing/validate_attestation.rs index 3b89bec99..cb26389df 100644 --- a/eth2/state_processing/src/per_block_processing/validate_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/validate_attestation.rs @@ -1,6 +1,6 @@ use super::errors::{AttestationInvalid as Invalid, AttestationValidationError as Error}; use crate::common::verify_bitfield_length; -use ssz::TreeHash; +use tree_hash::TreeHash; use types::*; /// Indicates if an `Attestation` is valid to be included in a block in the current epoch of the @@ -8,9 +8,9 @@ use types::*; /// /// Returns `Ok(())` if the `Attestation` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn validate_attestation( - state: &BeaconState, +/// Spec v0.5.1 +pub fn validate_attestation( + state: &BeaconState, attestation: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { @@ -18,8 +18,8 @@ pub fn validate_attestation( } /// Like `validate_attestation` but doesn't run checks which may become true in future states. -pub fn validate_attestation_time_independent_only( - state: &BeaconState, +pub fn validate_attestation_time_independent_only( + state: &BeaconState, attestation: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { @@ -31,9 +31,9 @@ pub fn validate_attestation_time_independent_only( /// /// Returns `Ok(())` if the `Attestation` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn validate_attestation_without_signature( - state: &BeaconState, +/// Spec v0.5.1 +pub fn validate_attestation_without_signature( + state: &BeaconState, attestation: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { @@ -44,9 +44,9 @@ pub fn validate_attestation_without_signature( /// given state, optionally validating the aggregate signature. /// /// -/// Spec v0.5.0 -fn validate_attestation_parametric( - state: &BeaconState, +/// Spec v0.5.1 +fn validate_attestation_parametric( + state: &BeaconState, attestation: &Attestation, spec: &ChainSpec, verify_signature: bool, @@ -167,10 +167,10 @@ fn validate_attestation_parametric( /// Verify that the `source_epoch` and `source_root` of an `Attestation` correctly /// match the current (or previous) justified epoch and root from the state. /// -/// Spec v0.5.0 -fn verify_justified_epoch_and_root( +/// Spec v0.5.1 +fn verify_justified_epoch_and_root( attestation: &Attestation, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), Error> { let state_epoch = state.slot.epoch(spec.slots_per_epoch); @@ -222,9 +222,9 @@ fn verify_justified_epoch_and_root( /// - `custody_bitfield` does not have a bit for each index of `committee`. /// - A `validator_index` in `committee` is not in `state.validator_registry`. /// -/// Spec v0.5.0 -fn verify_attestation_signature( - state: &BeaconState, +/// Spec v0.5.1 +fn verify_attestation_signature( + state: &BeaconState, committee: &[usize], a: &Attestation, spec: &ChainSpec, @@ -270,14 +270,14 @@ fn verify_attestation_signature( data: a.data.clone(), custody_bit: false, } - .hash_tree_root(); + .tree_hash_root(); // Message when custody bitfield is `true` let message_1 = AttestationDataAndCustodyBit { data: a.data.clone(), custody_bit: true, } - .hash_tree_root(); + .tree_hash_root(); let mut messages = vec![]; let mut keys = vec![]; diff --git a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs index abf99da64..5ac62221a 100644 --- a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs +++ b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs @@ -7,9 +7,9 @@ use types::*; /// /// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn verify_attester_slashing( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_attester_slashing( + state: &BeaconState, attester_slashing: &AttesterSlashing, should_verify_slashable_attestations: bool, spec: &ChainSpec, @@ -41,9 +41,9 @@ pub fn verify_attester_slashing( /// /// Returns Ok(indices) if `indices.len() > 0`. /// -/// Spec v0.5.0 -pub fn gather_attester_slashing_indices( - state: &BeaconState, +/// Spec v0.5.1 +pub fn gather_attester_slashing_indices( + state: &BeaconState, attester_slashing: &AttesterSlashing, spec: &ChainSpec, ) -> Result, Error> { @@ -57,8 +57,8 @@ pub fn gather_attester_slashing_indices( /// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria /// for determining whether a given validator should be considered slashed. -pub fn gather_attester_slashing_indices_modular( - state: &BeaconState, +pub fn gather_attester_slashing_indices_modular( + state: &BeaconState, attester_slashing: &AttesterSlashing, is_slashed: F, spec: &ChainSpec, diff --git a/eth2/state_processing/src/per_block_processing/verify_deposit.rs b/eth2/state_processing/src/per_block_processing/verify_deposit.rs index a3a0f5734..e2868a1b6 100644 --- a/eth2/state_processing/src/per_block_processing/verify_deposit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_deposit.rs @@ -15,9 +15,9 @@ use types::*; /// /// Note: this function is incomplete. /// -/// Spec v0.5.0 -pub fn verify_deposit( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_deposit( + state: &BeaconState, deposit: &Deposit, verify_merkle_branch: bool, spec: &ChainSpec, @@ -46,8 +46,11 @@ pub fn verify_deposit( /// Verify that the `Deposit` index is correct. /// -/// Spec v0.5.0 -pub fn verify_deposit_index(state: &BeaconState, deposit: &Deposit) -> Result<(), Error> { +/// Spec v0.5.1 +pub fn verify_deposit_index( + state: &BeaconState, + deposit: &Deposit, +) -> Result<(), Error> { verify!( deposit.index == state.deposit_index, Invalid::BadIndex { @@ -65,8 +68,8 @@ pub fn verify_deposit_index(state: &BeaconState, deposit: &Deposit) -> Result<() /// ## Errors /// /// Errors if the state's `pubkey_cache` is not current. -pub fn get_existing_validator_index( - state: &BeaconState, +pub fn get_existing_validator_index( + state: &BeaconState, deposit: &Deposit, ) -> Result, Error> { let deposit_input = &deposit.deposit_data.deposit_input; @@ -88,12 +91,16 @@ pub fn get_existing_validator_index( /// Verify that a deposit is included in the state's eth1 deposit root. /// -/// Spec v0.5.0 -fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &ChainSpec) -> bool { +/// Spec v0.5.1 +fn verify_deposit_merkle_proof( + state: &BeaconState, + deposit: &Deposit, + spec: &ChainSpec, +) -> bool { let leaf = hash(&get_serialized_deposit_data(deposit)); verify_merkle_proof( Hash256::from_slice(&leaf), - &deposit.proof, + &deposit.proof[..], spec.deposit_contract_tree_depth as usize, deposit.index as usize, state.latest_eth1_data.deposit_root, @@ -102,7 +109,7 @@ fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &Ch /// Helper struct for easily getting the serialized data generated by the deposit contract. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive(Encode)] struct SerializedDepositData { amount: u64, @@ -113,7 +120,7 @@ struct SerializedDepositData { /// Return the serialized data generated by the deposit contract that is used to generate the /// merkle proof. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn get_serialized_deposit_data(deposit: &Deposit) -> Vec { let serialized_deposit_data = SerializedDepositData { amount: deposit.deposit_data.amount, diff --git a/eth2/state_processing/src/per_block_processing/verify_exit.rs b/eth2/state_processing/src/per_block_processing/verify_exit.rs index a3b694395..333638a8d 100644 --- a/eth2/state_processing/src/per_block_processing/verify_exit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_exit.rs @@ -1,5 +1,5 @@ use super::errors::{ExitInvalid as Invalid, ExitValidationError as Error}; -use ssz::SignedRoot; +use tree_hash::SignedRoot; use types::*; /// Indicates if an `Exit` is valid to be included in a block in the current epoch of the given @@ -7,9 +7,9 @@ use types::*; /// /// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn verify_exit( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_exit( + state: &BeaconState, exit: &VoluntaryExit, spec: &ChainSpec, ) -> Result<(), Error> { @@ -17,8 +17,8 @@ pub fn verify_exit( } /// Like `verify_exit` but doesn't run checks which may become true in future states. -pub fn verify_exit_time_independent_only( - state: &BeaconState, +pub fn verify_exit_time_independent_only( + state: &BeaconState, exit: &VoluntaryExit, spec: &ChainSpec, ) -> Result<(), Error> { @@ -26,8 +26,8 @@ pub fn verify_exit_time_independent_only( } /// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true. -fn verify_exit_parametric( - state: &BeaconState, +fn verify_exit_parametric( + state: &BeaconState, exit: &VoluntaryExit, spec: &ChainSpec, time_independent_only: bool, diff --git a/eth2/state_processing/src/per_block_processing/verify_proposer_slashing.rs b/eth2/state_processing/src/per_block_processing/verify_proposer_slashing.rs index dffb9d898..0c66a9b15 100644 --- a/eth2/state_processing/src/per_block_processing/verify_proposer_slashing.rs +++ b/eth2/state_processing/src/per_block_processing/verify_proposer_slashing.rs @@ -1,5 +1,5 @@ use super::errors::{ProposerSlashingInvalid as Invalid, ProposerSlashingValidationError as Error}; -use ssz::SignedRoot; +use tree_hash::SignedRoot; use types::*; /// Indicates if a `ProposerSlashing` is valid to be included in a block in the current epoch of the given @@ -7,10 +7,10 @@ use types::*; /// /// Returns `Ok(())` if the `ProposerSlashing` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn verify_proposer_slashing( +/// Spec v0.5.1 +pub fn verify_proposer_slashing( proposer_slashing: &ProposerSlashing, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), Error> { let proposer = state @@ -21,8 +21,9 @@ pub fn verify_proposer_slashing( })?; verify!( - proposer_slashing.header_1.slot == proposer_slashing.header_2.slot, - Invalid::ProposalSlotMismatch( + proposer_slashing.header_1.slot.epoch(spec.slots_per_epoch) + == proposer_slashing.header_2.slot.epoch(spec.slots_per_epoch), + Invalid::ProposalEpochMismatch( proposer_slashing.header_1.slot, proposer_slashing.header_2.slot ) @@ -66,7 +67,7 @@ pub fn verify_proposer_slashing( /// /// Returns `true` if the signature is valid. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn verify_header_signature( header: &BeaconBlockHeader, pubkey: &PublicKey, diff --git a/eth2/state_processing/src/per_block_processing/verify_slashable_attestation.rs b/eth2/state_processing/src/per_block_processing/verify_slashable_attestation.rs index d3ab5e398..4d440332a 100644 --- a/eth2/state_processing/src/per_block_processing/verify_slashable_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/verify_slashable_attestation.rs @@ -2,7 +2,7 @@ use super::errors::{ SlashableAttestationInvalid as Invalid, SlashableAttestationValidationError as Error, }; use crate::common::verify_bitfield_length; -use ssz::TreeHash; +use tree_hash::TreeHash; use types::*; /// Indicates if a `SlashableAttestation` is valid to be included in a block in the current epoch of the given @@ -10,9 +10,9 @@ use types::*; /// /// Returns `Ok(())` if the `SlashableAttestation` is valid, otherwise indicates the reason for invalidity. /// -/// Spec v0.5.0 -pub fn verify_slashable_attestation( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_slashable_attestation( + state: &BeaconState, slashable_attestation: &SlashableAttestation, spec: &ChainSpec, ) -> Result<(), Error> { @@ -77,12 +77,12 @@ pub fn verify_slashable_attestation( data: slashable_attestation.data.clone(), custody_bit: false, } - .hash_tree_root(); + .tree_hash_root(); let message_1 = AttestationDataAndCustodyBit { data: slashable_attestation.data.clone(), custody_bit: true, } - .hash_tree_root(); + .tree_hash_root(); let mut messages = vec![]; let mut keys = vec![]; diff --git a/eth2/state_processing/src/per_block_processing/verify_transfer.rs b/eth2/state_processing/src/per_block_processing/verify_transfer.rs index ac9e9aa09..c6388bebe 100644 --- a/eth2/state_processing/src/per_block_processing/verify_transfer.rs +++ b/eth2/state_processing/src/per_block_processing/verify_transfer.rs @@ -1,6 +1,6 @@ use super::errors::{TransferInvalid as Invalid, TransferValidationError as Error}; use bls::get_withdrawal_credentials; -use ssz::SignedRoot; +use tree_hash::SignedRoot; use types::*; /// Indicates if a `Transfer` is valid to be included in a block in the current epoch of the given @@ -10,9 +10,9 @@ use types::*; /// /// Note: this function is incomplete. /// -/// Spec v0.5.0 -pub fn verify_transfer( - state: &BeaconState, +/// Spec v0.5.1 +pub fn verify_transfer( + state: &BeaconState, transfer: &Transfer, spec: &ChainSpec, ) -> Result<(), Error> { @@ -20,8 +20,8 @@ pub fn verify_transfer( } /// Like `verify_transfer` but doesn't run checks which may become true in future states. -pub fn verify_transfer_time_independent_only( - state: &BeaconState, +pub fn verify_transfer_time_independent_only( + state: &BeaconState, transfer: &Transfer, spec: &ChainSpec, ) -> Result<(), Error> { @@ -29,8 +29,8 @@ pub fn verify_transfer_time_independent_only( } /// Parametric version of `verify_transfer` that allows some checks to be skipped. -fn verify_transfer_parametric( - state: &BeaconState, +fn verify_transfer_parametric( + state: &BeaconState, transfer: &Transfer, spec: &ChainSpec, time_independent_only: bool, @@ -122,9 +122,9 @@ fn verify_transfer_parametric( /// /// Does not check that the transfer is valid, however checks for overflow in all actions. /// -/// Spec v0.5.0 -pub fn execute_transfer( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn execute_transfer( + state: &mut BeaconState, transfer: &Transfer, spec: &ChainSpec, ) -> Result<(), Error> { diff --git a/eth2/state_processing/src/per_epoch_processing.rs b/eth2/state_processing/src/per_epoch_processing.rs index fcdc668f4..3f8eb5112 100644 --- a/eth2/state_processing/src/per_epoch_processing.rs +++ b/eth2/state_processing/src/per_epoch_processing.rs @@ -3,8 +3,8 @@ use errors::EpochProcessingError as Error; use process_ejections::process_ejections; use process_exit_queue::process_exit_queue; use process_slashings::process_slashings; -use ssz::TreeHash; use std::collections::HashMap; +use tree_hash::TreeHash; use types::*; use update_registry_and_shuffling_data::update_registry_and_shuffling_data; use validator_statuses::{TotalBalances, ValidatorStatuses}; @@ -32,8 +32,11 @@ pub type WinningRootHashSet = HashMap; /// Mutates the given `BeaconState`, returning early if an error is encountered. If an error is /// returned, a state might be "half-processed" and therefore in an invalid state. /// -/// Spec v0.5.0 -pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { +/// Spec v0.5.1 +pub fn per_epoch_processing( + state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { // Ensure the previous and next epoch caches are built. state.build_epoch_cache(RelativeEpoch::Previous, spec)?; state.build_epoch_cache(RelativeEpoch::Current, spec)?; @@ -86,8 +89,8 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result /// Maybe resets the eth1 period. /// -/// Spec v0.5.0 -pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) { +/// Spec v0.5.1 +pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) { let next_epoch = state.next_epoch(spec); let voting_period = spec.epochs_per_eth1_voting_period; @@ -108,9 +111,9 @@ pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) { /// - `justified_epoch` /// - `previous_justified_epoch` /// -/// Spec v0.5.0 -pub fn update_justification_and_finalization( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn update_justification_and_finalization( + state: &mut BeaconState, total_balances: &TotalBalances, spec: &ChainSpec, ) -> Result<(), Error> { @@ -160,13 +163,13 @@ pub fn update_justification_and_finalization( if new_justified_epoch != state.current_justified_epoch { state.current_justified_epoch = new_justified_epoch; state.current_justified_root = - *state.get_block_root(new_justified_epoch.start_slot(spec.slots_per_epoch), spec)?; + *state.get_block_root(new_justified_epoch.start_slot(spec.slots_per_epoch))?; } if new_finalized_epoch != state.finalized_epoch { state.finalized_epoch = new_finalized_epoch; state.finalized_root = - *state.get_block_root(new_finalized_epoch.start_slot(spec.slots_per_epoch), spec)?; + *state.get_block_root(new_finalized_epoch.start_slot(spec.slots_per_epoch))?; } Ok(()) @@ -178,9 +181,9 @@ pub fn update_justification_and_finalization( /// /// Also returns a `WinningRootHashSet` for later use during epoch processing. /// -/// Spec v0.5.0 -pub fn process_crosslinks( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_crosslinks( + state: &mut BeaconState, spec: &ChainSpec, ) -> Result { let mut winning_root_for_shards: WinningRootHashSet = HashMap::new(); @@ -221,8 +224,11 @@ pub fn process_crosslinks( /// Finish up an epoch update. /// -/// Spec v0.5.0 -pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { +/// Spec v0.5.1 +pub fn finish_epoch_update( + state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { let current_epoch = state.current_epoch(spec); let next_epoch = state.next_epoch(spec); @@ -236,16 +242,12 @@ pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result< let active_index_root = Hash256::from_slice( &state .get_active_validator_indices(next_epoch + spec.activation_exit_delay) - .hash_tree_root()[..], + .tree_hash_root()[..], ); state.set_active_index_root(next_epoch, active_index_root, spec)?; // Set total slashed balances - state.set_slashed_balance( - next_epoch, - state.get_slashed_balance(current_epoch, spec)?, - spec, - )?; + state.set_slashed_balance(next_epoch, state.get_slashed_balance(current_epoch)?)?; // Set randao mix state.set_randao_mix( @@ -257,11 +259,11 @@ pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result< state.slot -= 1; } - if next_epoch.as_u64() % (spec.slots_per_historical_root as u64 / spec.slots_per_epoch) == 0 { - let historical_batch: HistoricalBatch = state.historical_batch(); + if next_epoch.as_u64() % (T::SlotsPerHistoricalRoot::to_u64() / spec.slots_per_epoch) == 0 { + let historical_batch = state.historical_batch(); state .historical_roots - .push(Hash256::from_slice(&historical_batch.hash_tree_root()[..])); + .push(Hash256::from_slice(&historical_batch.tree_hash_root()[..])); } state.previous_epoch_attestations = state.current_epoch_attestations.clone(); diff --git a/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs index ce5fccb21..f529523fb 100644 --- a/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs +++ b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs @@ -32,9 +32,9 @@ impl std::ops::AddAssign for Delta { /// Apply attester and proposer rewards. /// -/// Spec v0.5.0 -pub fn apply_rewards( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn apply_rewards( + state: &mut BeaconState, validator_statuses: &mut ValidatorStatuses, winning_root_for_shards: &WinningRootHashSet, spec: &ChainSpec, @@ -79,10 +79,10 @@ pub fn apply_rewards( /// Applies the attestation inclusion reward to each proposer for every validator who included an /// attestation in the previous epoch. /// -/// Spec v0.5.0 -fn get_proposer_deltas( +/// Spec v0.5.1 +fn get_proposer_deltas( deltas: &mut Vec, - state: &mut BeaconState, + state: &mut BeaconState, validator_statuses: &mut ValidatorStatuses, winning_root_for_shards: &WinningRootHashSet, spec: &ChainSpec, @@ -120,10 +120,10 @@ fn get_proposer_deltas( /// Apply rewards for participation in attestations during the previous epoch. /// -/// Spec v0.5.0 -fn get_justification_and_finalization_deltas( +/// Spec v0.5.1 +fn get_justification_and_finalization_deltas( deltas: &mut Vec, - state: &BeaconState, + state: &BeaconState, validator_statuses: &ValidatorStatuses, spec: &ChainSpec, ) -> Result<(), Error> { @@ -163,7 +163,7 @@ fn get_justification_and_finalization_deltas( /// Determine the delta for a single validator, if the chain is finalizing normally. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn compute_normal_justification_and_finalization_delta( validator: &ValidatorStatus, total_balances: &TotalBalances, @@ -215,7 +215,7 @@ fn compute_normal_justification_and_finalization_delta( /// Determine the delta for a single delta, assuming the chain is _not_ finalizing normally. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn compute_inactivity_leak_delta( validator: &ValidatorStatus, base_reward: u64, @@ -261,10 +261,10 @@ fn compute_inactivity_leak_delta( /// Calculate the deltas based upon the winning roots for attestations during the previous epoch. /// -/// Spec v0.5.0 -fn get_crosslink_deltas( +/// Spec v0.5.1 +fn get_crosslink_deltas( deltas: &mut Vec, - state: &BeaconState, + state: &BeaconState, validator_statuses: &ValidatorStatuses, spec: &ChainSpec, ) -> Result<(), Error> { @@ -295,9 +295,9 @@ fn get_crosslink_deltas( /// Returns the base reward for some validator. /// -/// Spec v0.5.0 -fn get_base_reward( - state: &BeaconState, +/// Spec v0.5.1 +fn get_base_reward( + state: &BeaconState, index: usize, previous_total_balance: u64, spec: &ChainSpec, @@ -312,9 +312,9 @@ fn get_base_reward( /// Returns the inactivity penalty for some validator. /// -/// Spec v0.5.0 -fn get_inactivity_penalty( - state: &BeaconState, +/// Spec v0.5.1 +fn get_inactivity_penalty( + state: &BeaconState, index: usize, epochs_since_finality: u64, previous_total_balance: u64, @@ -328,7 +328,7 @@ fn get_inactivity_penalty( /// Returns the epochs since the last finalized epoch. /// -/// Spec v0.5.0 -fn epochs_since_finality(state: &BeaconState, spec: &ChainSpec) -> Epoch { +/// Spec v0.5.1 +fn epochs_since_finality(state: &BeaconState, spec: &ChainSpec) -> Epoch { state.current_epoch(spec) + 1 - state.finalized_epoch } diff --git a/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs b/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs index 52ba0274b..7f5504c56 100644 --- a/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs +++ b/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs @@ -3,9 +3,9 @@ use types::*; /// Returns validator indices which participated in the attestation. /// -/// Spec v0.5.0 -pub fn get_attestation_participants( - state: &BeaconState, +/// Spec v0.5.1 +pub fn get_attestation_participants( + state: &BeaconState, attestation_data: &AttestationData, bitfield: &Bitfield, spec: &ChainSpec, diff --git a/eth2/state_processing/src/per_epoch_processing/inclusion_distance.rs b/eth2/state_processing/src/per_epoch_processing/inclusion_distance.rs index b52485947..e82d810ba 100644 --- a/eth2/state_processing/src/per_epoch_processing/inclusion_distance.rs +++ b/eth2/state_processing/src/per_epoch_processing/inclusion_distance.rs @@ -5,9 +5,9 @@ use types::*; /// Returns the distance between the first included attestation for some validator and this /// slot. /// -/// Spec v0.5.0 -pub fn inclusion_distance( - state: &BeaconState, +/// Spec v0.5.1 +pub fn inclusion_distance( + state: &BeaconState, attestations: &[&PendingAttestation], validator_index: usize, spec: &ChainSpec, @@ -18,9 +18,9 @@ pub fn inclusion_distance( /// Returns the slot of the earliest included attestation for some validator. /// -/// Spec v0.5.0 -pub fn inclusion_slot( - state: &BeaconState, +/// Spec v0.5.1 +pub fn inclusion_slot( + state: &BeaconState, attestations: &[&PendingAttestation], validator_index: usize, spec: &ChainSpec, @@ -31,9 +31,9 @@ pub fn inclusion_slot( /// Finds the earliest included attestation for some validator. /// -/// Spec v0.5.0 -fn earliest_included_attestation( - state: &BeaconState, +/// Spec v0.5.1 +fn earliest_included_attestation( + state: &BeaconState, attestations: &[&PendingAttestation], validator_index: usize, spec: &ChainSpec, diff --git a/eth2/state_processing/src/per_epoch_processing/process_ejections.rs b/eth2/state_processing/src/per_epoch_processing/process_ejections.rs index a60d92187..e32241e24 100644 --- a/eth2/state_processing/src/per_epoch_processing/process_ejections.rs +++ b/eth2/state_processing/src/per_epoch_processing/process_ejections.rs @@ -4,8 +4,11 @@ use types::{BeaconStateError as Error, *}; /// Iterate through the validator registry and eject active validators with balance below /// ``EJECTION_BALANCE``. /// -/// Spec v0.5.0 -pub fn process_ejections(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { +/// Spec v0.5.1 +pub fn process_ejections( + state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { // There is an awkward double (triple?) loop here because we can't loop across the borrowed // active validator indices and mutate state in the one loop. let exitable: Vec = state diff --git a/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs b/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs index 074db1d08..eafe4541e 100644 --- a/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs +++ b/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs @@ -2,8 +2,8 @@ use types::*; /// Process the exit queue. /// -/// Spec v0.5.0 -pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) { +/// Spec v0.5.1 +pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) { let current_epoch = state.current_epoch(spec); let eligible = |index: usize| { @@ -31,9 +31,9 @@ pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) { /// Initiate an exit for the validator of the given `index`. /// -/// Spec v0.5.0 -fn prepare_validator_for_withdrawal( - state: &mut BeaconState, +/// Spec v0.5.1 +fn prepare_validator_for_withdrawal( + state: &mut BeaconState, validator_index: usize, spec: &ChainSpec, ) { diff --git a/eth2/state_processing/src/per_epoch_processing/process_slashings.rs b/eth2/state_processing/src/per_epoch_processing/process_slashings.rs index 88777472c..a70720cce 100644 --- a/eth2/state_processing/src/per_epoch_processing/process_slashings.rs +++ b/eth2/state_processing/src/per_epoch_processing/process_slashings.rs @@ -2,21 +2,21 @@ use types::{BeaconStateError as Error, *}; /// Process slashings. /// -/// Spec v0.5.0 -pub fn process_slashings( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn process_slashings( + state: &mut BeaconState, current_total_balance: u64, spec: &ChainSpec, ) -> Result<(), Error> { let current_epoch = state.current_epoch(spec); - let total_at_start = state.get_slashed_balance(current_epoch + 1, spec)?; - let total_at_end = state.get_slashed_balance(current_epoch, spec)?; + let total_at_start = state.get_slashed_balance(current_epoch + 1)?; + let total_at_end = state.get_slashed_balance(current_epoch)?; let total_penalities = total_at_end - total_at_start; for (index, validator) in state.validator_registry.iter().enumerate() { let should_penalize = current_epoch.as_usize() - == validator.withdrawable_epoch.as_usize() - spec.latest_slashed_exit_length / 2; + == validator.withdrawable_epoch.as_usize() - T::LatestSlashedExitLength::to_usize() / 2; if validator.slashed && should_penalize { let effective_balance = state.get_effective_balance(index, spec)?; diff --git a/eth2/state_processing/src/per_epoch_processing/tests.rs b/eth2/state_processing/src/per_epoch_processing/tests.rs index 69450edcd..b075c5cd4 100644 --- a/eth2/state_processing/src/per_epoch_processing/tests.rs +++ b/eth2/state_processing/src/per_epoch_processing/tests.rs @@ -8,9 +8,10 @@ use types::*; fn runs_without_error() { Builder::from_env(Env::default().default_filter_or("error")).init(); - let spec = ChainSpec::few_validators(); + let spec = FewValidatorsEthSpec::spec(); - let mut builder = TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec); + let mut builder: TestingBeaconStateBuilder = + TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec); let target_slot = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch); builder.teleport_to_slot(target_slot, &spec); diff --git a/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs index 0b18c2571..f6548fb67 100644 --- a/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs +++ b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs @@ -4,9 +4,9 @@ use types::*; /// Peforms a validator registry update, if required. /// -/// Spec v0.5.0 -pub fn update_registry_and_shuffling_data( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn update_registry_and_shuffling_data( + state: &mut BeaconState, current_total_balance: u64, spec: &ChainSpec, ) -> Result<(), Error> { @@ -49,9 +49,9 @@ pub fn update_registry_and_shuffling_data( /// Returns `true` if the validator registry should be updated during an epoch processing. /// -/// Spec v0.5.0 -pub fn should_update_validator_registry( - state: &BeaconState, +/// Spec v0.5.1 +pub fn should_update_validator_registry( + state: &BeaconState, spec: &ChainSpec, ) -> Result { if state.finalized_epoch <= state.validator_registry_update_epoch { @@ -78,9 +78,9 @@ pub fn should_update_validator_registry( /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// -/// Spec v0.5.0 -pub fn update_validator_registry( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn update_validator_registry( + state: &mut BeaconState, current_total_balance: u64, spec: &ChainSpec, ) -> Result<(), Error> { @@ -133,9 +133,9 @@ pub fn update_validator_registry( /// Activate the validator of the given ``index``. /// -/// Spec v0.5.0 -pub fn activate_validator( - state: &mut BeaconState, +/// Spec v0.5.1 +pub fn activate_validator( + state: &mut BeaconState, validator_index: usize, is_genesis: bool, spec: &ChainSpec, diff --git a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs index 02149cc5a..ee0079eee 100644 --- a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs +++ b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs @@ -160,8 +160,11 @@ impl ValidatorStatuses { /// - Active validators /// - Total balances for the current and previous epochs. /// - /// Spec v0.5.0 - pub fn new(state: &BeaconState, spec: &ChainSpec) -> Result { + /// Spec v0.5.1 + pub fn new( + state: &BeaconState, + spec: &ChainSpec, + ) -> Result { let mut statuses = Vec::with_capacity(state.validator_registry.len()); let mut total_balances = TotalBalances::default(); @@ -195,10 +198,10 @@ impl ValidatorStatuses { /// Process some attestations from the given `state` updating the `statuses` and /// `total_balances` fields. /// - /// Spec v0.5.0 - pub fn process_attestations( + /// Spec v0.5.1 + pub fn process_attestations( &mut self, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) -> Result<(), BeaconStateError> { for a in state @@ -243,7 +246,7 @@ impl ValidatorStatuses { status.is_previous_epoch_boundary_attester = true; } - if has_common_beacon_block_root(a, state, spec)? { + if has_common_beacon_block_root(a, state)? { self.total_balances.previous_epoch_head_attesters += attesting_balance; status.is_previous_epoch_head_attester = true; } @@ -261,10 +264,10 @@ impl ValidatorStatuses { /// Update the `statuses` for each validator based upon whether or not they attested to the /// "winning" shard block root for the previous epoch. /// - /// Spec v0.5.0 - pub fn process_winning_roots( + /// Spec v0.5.1 + pub fn process_winning_roots( &mut self, - state: &BeaconState, + state: &BeaconState, winning_roots: &WinningRootHashSet, spec: &ChainSpec, ) -> Result<(), BeaconStateError> { @@ -297,14 +300,14 @@ impl ValidatorStatuses { /// Returns the distance between when the attestation was created and when it was included in a /// block. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn inclusion_distance(a: &PendingAttestation) -> Slot { a.inclusion_slot - a.data.slot } /// Returns `true` if some `PendingAttestation` is from the supplied `epoch`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 fn is_from_epoch(a: &PendingAttestation, epoch: Epoch, spec: &ChainSpec) -> bool { a.data.slot.epoch(spec.slots_per_epoch) == epoch } @@ -312,15 +315,15 @@ fn is_from_epoch(a: &PendingAttestation, epoch: Epoch, spec: &ChainSpec) -> bool /// Returns `true` if a `PendingAttestation` and `BeaconState` share the same beacon block hash for /// the first slot of the given epoch. /// -/// Spec v0.5.0 -fn has_common_epoch_boundary_root( +/// Spec v0.5.1 +fn has_common_epoch_boundary_root( a: &PendingAttestation, - state: &BeaconState, + state: &BeaconState, epoch: Epoch, spec: &ChainSpec, ) -> Result { let slot = epoch.start_slot(spec.slots_per_epoch); - let state_boundary_root = *state.get_block_root(slot, spec)?; + let state_boundary_root = *state.get_block_root(slot)?; Ok(a.data.target_root == state_boundary_root) } @@ -328,13 +331,12 @@ fn has_common_epoch_boundary_root( /// Returns `true` if a `PendingAttestation` and `BeaconState` share the same beacon block hash for /// the current slot of the `PendingAttestation`. /// -/// Spec v0.5.0 -fn has_common_beacon_block_root( +/// Spec v0.5.1 +fn has_common_beacon_block_root( a: &PendingAttestation, - state: &BeaconState, - spec: &ChainSpec, + state: &BeaconState, ) -> Result { - let state_block_root = *state.get_block_root(a.data.slot, spec)?; + let state_block_root = *state.get_block_root(a.data.slot)?; Ok(a.data.beacon_block_root == state_block_root) } diff --git a/eth2/state_processing/src/per_epoch_processing/winning_root.rs b/eth2/state_processing/src/per_epoch_processing/winning_root.rs index 97cff3e13..8ffa717e8 100644 --- a/eth2/state_processing/src/per_epoch_processing/winning_root.rs +++ b/eth2/state_processing/src/per_epoch_processing/winning_root.rs @@ -16,7 +16,7 @@ impl WinningRoot { /// A winning root is "better" than another if it has a higher `total_attesting_balance`. Ties /// are broken by favouring the higher `crosslink_data_root` value. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn is_better_than(&self, other: &Self) -> bool { if self.total_attesting_balance > other.total_attesting_balance { true @@ -34,9 +34,9 @@ impl WinningRoot { /// The `WinningRoot` object also contains additional fields that are useful in later stages of /// per-epoch processing. /// -/// Spec v0.5.0 -pub fn winning_root( - state: &BeaconState, +/// Spec v0.5.1 +pub fn winning_root( + state: &BeaconState, shard: u64, spec: &ChainSpec, ) -> Result, BeaconStateError> { @@ -89,8 +89,12 @@ pub fn winning_root( /// Returns `true` if pending attestation `a` is eligible to become a winning root. /// -/// Spec v0.5.0 -fn is_eligible_for_winning_root(state: &BeaconState, a: &PendingAttestation, shard: Shard) -> bool { +/// Spec v0.5.1 +fn is_eligible_for_winning_root( + state: &BeaconState, + a: &PendingAttestation, + shard: Shard, +) -> bool { if shard >= state.latest_crosslinks.len() as u64 { return false; } @@ -100,9 +104,9 @@ fn is_eligible_for_winning_root(state: &BeaconState, a: &PendingAttestation, sha /// Returns all indices which voted for a given crosslink. Does not contain duplicates. /// -/// Spec v0.5.0 -fn get_attesting_validator_indices( - state: &BeaconState, +/// Spec v0.5.1 +fn get_attesting_validator_indices( + state: &BeaconState, shard: u64, crosslink_data_root: &Hash256, spec: &ChainSpec, diff --git a/eth2/state_processing/src/per_slot_processing.rs b/eth2/state_processing/src/per_slot_processing.rs index c6b5312c7..ebab36ff7 100644 --- a/eth2/state_processing/src/per_slot_processing.rs +++ b/eth2/state_processing/src/per_slot_processing.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::TreeHash; +use tree_hash::SignedRoot; use types::*; #[derive(Debug, PartialEq)] @@ -10,13 +10,12 @@ pub enum Error { /// Advances a state forward by one slot, performing per-epoch processing if required. /// -/// Spec v0.5.0 -pub fn per_slot_processing( - state: &mut BeaconState, - latest_block_header: &BeaconBlockHeader, +/// Spec v0.5.1 +pub fn per_slot_processing( + state: &mut BeaconState, spec: &ChainSpec, ) -> Result<(), Error> { - cache_state(state, latest_block_header, spec)?; + cache_state(state, spec)?; if (state.slot + 1) % spec.slots_per_epoch == 0 { per_epoch_processing(state, spec)?; @@ -27,12 +26,8 @@ pub fn per_slot_processing( Ok(()) } -fn cache_state( - state: &mut BeaconState, - latest_block_header: &BeaconBlockHeader, - spec: &ChainSpec, -) -> Result<(), Error> { - let previous_slot_state_root = Hash256::from_slice(&state.hash_tree_root()[..]); +fn cache_state(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { + let previous_slot_state_root = state.update_tree_hash_cache()?; // Note: increment the state slot here to allow use of our `state_root` and `block_root` // getter/setter functions. @@ -46,8 +41,11 @@ fn cache_state( state.latest_block_header.state_root = previous_slot_state_root } - let latest_block_root = Hash256::from_slice(&latest_block_header.hash_tree_root()[..]); - state.set_block_root(previous_slot, latest_block_root, spec)?; + // Store the previous slot's post state transition root. + state.set_state_root(previous_slot, previous_slot_state_root)?; + + let latest_block_root = Hash256::from_slice(&state.latest_block_header.signed_root()[..]); + state.set_block_root(previous_slot, latest_block_root)?; // Set the state slot back to what it should be. state.slot -= 1; diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs deleted file mode 100644 index 25613f9a7..000000000 --- a/eth2/state_processing/tests/tests.rs +++ /dev/null @@ -1,108 +0,0 @@ -#![cfg(not(debug_assertions))] - -use serde_derive::Deserialize; -use serde_yaml; -use state_processing::{ - per_block_processing, per_block_processing_without_verifying_block_signature, - per_slot_processing, -}; -use std::{fs::File, io::prelude::*, path::PathBuf}; -use types::*; -#[allow(unused_imports)] -use yaml_utils; - -#[derive(Debug, Deserialize)] -pub struct TestCase { - pub name: String, - pub config: ChainSpec, - pub verify_signatures: bool, - pub initial_state: BeaconState, - pub blocks: Vec, -} - -#[derive(Debug, Deserialize)] -pub struct TestDoc { - pub title: String, - pub summary: String, - pub fork: String, - pub test_cases: Vec, -} - -#[test] -fn test_read_yaml() { - // Test sanity-check_small-config_32-vals.yaml - let mut file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml"); - - File::open(file_path_buf).unwrap() - }; - - let mut yaml_str = String::new(); - - file.read_to_string(&mut yaml_str).unwrap(); - - yaml_str = yaml_str.to_lowercase(); - - let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); - - // Test sanity-check_default-config_100-vals.yaml - file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml"); - - File::open(file_path_buf).unwrap() - }; - - yaml_str = String::new(); - - file.read_to_string(&mut yaml_str).unwrap(); - - yaml_str = yaml_str.to_lowercase(); - - let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); -} - -#[test] -fn run_state_transition_tests_small() { - // Test sanity-check_small-config_32-vals.yaml - let mut file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml"); - - File::open(file_path_buf).unwrap() - }; - let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); - yaml_str = yaml_str.to_lowercase(); - - let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); - - // Run Tests - for (i, test_case) in doc.test_cases.iter().enumerate() { - let mut state = test_case.initial_state.clone(); - for block in test_case.blocks.iter() { - while block.slot > state.slot { - let latest_block_header = state.latest_block_header.clone(); - per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap(); - } - if test_case.verify_signatures { - let res = per_block_processing(&mut state, &block, &test_case.config); - if res.is_err() { - println!("{:?}", i); - println!("{:?}", res); - }; - } else { - let res = per_block_processing_without_verifying_block_signature( - &mut state, - &block, - &test_case.config, - ); - if res.is_err() { - println!("{:?}", i); - println!("{:?}", res); - } - } - } - } -} diff --git a/eth2/state_processing/yaml_utils/Cargo.toml b/eth2/state_processing/yaml_utils/Cargo.toml deleted file mode 100644 index 4a7ae5b89..000000000 --- a/eth2/state_processing/yaml_utils/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "yaml-utils" -version = "0.1.0" -authors = ["Kirk Baird "] -edition = "2018" - -[build-dependencies] -reqwest = "0.9" -tempdir = "0.3" - -[dependencies] - -[lib] -name = "yaml_utils" -path = "src/lib.rs" diff --git a/eth2/state_processing/yaml_utils/build.rs b/eth2/state_processing/yaml_utils/build.rs deleted file mode 100644 index 3b7f31471..000000000 --- a/eth2/state_processing/yaml_utils/build.rs +++ /dev/null @@ -1,28 +0,0 @@ -extern crate reqwest; -extern crate tempdir; - -use std::fs::File; -use std::io::copy; - -fn main() { - // These test files are not to be stored in the lighthouse repo as they are quite large (32MB). - // They will be downloaded at build time by yaml-utils crate (in build.rs) - let git_path = "https://raw.githubusercontent.com/ethereum/eth2.0-tests/master/state/"; - let test_names = vec![ - "sanity-check_default-config_100-vals.yaml", - "sanity-check_small-config_32-vals.yaml", - ]; - - for test in test_names { - let mut target = String::from(git_path); - target.push_str(test); - let mut response = reqwest::get(target.as_str()).unwrap(); - - let mut dest = { - let mut file_name = String::from("specs/"); - file_name.push_str(test); - File::create(file_name).unwrap() - }; - copy(&mut response, &mut dest).unwrap(); - } -} diff --git a/eth2/state_processing/yaml_utils/specs/.gitignore b/eth2/state_processing/yaml_utils/specs/.gitignore deleted file mode 100644 index 1e82fc7de..000000000 --- a/eth2/state_processing/yaml_utils/specs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.yaml diff --git a/eth2/state_processing/yaml_utils/src/lib.rs b/eth2/state_processing/yaml_utils/src/lib.rs deleted file mode 100644 index 644ea434b..000000000 --- a/eth2/state_processing/yaml_utils/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -// This is a place holder such that yaml-utils is now a crate hence build.rs will be run when 'cargo test' is called diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index 613eb7936..160697edd 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -7,9 +7,11 @@ edition = "2018" [dependencies] bls = { path = "../utils/bls" } boolean-bitfield = { path = "../utils/boolean-bitfield" } +cached_tree_hash = { path = "../utils/cached_tree_hash" } dirs = "1.0" derivative = "1.0" ethereum-types = "0.5" +fixed_len_vec = { path = "../utils/fixed_len_vec" } hashing = { path = "../utils/hashing" } hex = "0.3" honey-badger-split = { path = "../utils/honey-badger-split" } @@ -26,6 +28,8 @@ ssz = { path = "../utils/ssz" } ssz_derive = { path = "../utils/ssz_derive" } swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } test_random_derive = { path = "../utils/test_random_derive" } +tree_hash = { path = "../utils/tree_hash" } +tree_hash_derive = { path = "../utils/tree_hash_derive" } libp2p = { git = "https://github.com/SigP/rust-libp2p", rev = "b3c32d9a821ae6cc89079499cc6e8a6bab0bffc3" } [dev-dependencies] diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index a8eeea909..d6d5d3a22 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -1,14 +1,15 @@ use super::{AggregateSignature, AttestationData, Bitfield}; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// Details an attestation that can be slashable. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, Clone, @@ -18,6 +19,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -57,4 +59,5 @@ mod tests { use super::*; ssz_tests!(Attestation); + cached_tree_hash_tests!(Attestation); } diff --git a/eth2/types/src/attestation_data.rs b/eth2/types/src/attestation_data.rs index 4a6b57823..60e539ab8 100644 --- a/eth2/types/src/attestation_data.rs +++ b/eth2/types/src/attestation_data.rs @@ -1,14 +1,15 @@ use crate::test_utils::TestRandom; use crate::{Crosslink, Epoch, Hash256, Slot}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// The data upon which an attestation is based. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, Clone, @@ -20,6 +21,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -46,4 +48,5 @@ mod tests { use super::*; ssz_tests!(AttestationData); + cached_tree_hash_tests!(AttestationData); } diff --git a/eth2/types/src/attestation_data_and_custody_bit.rs b/eth2/types/src/attestation_data_and_custody_bit.rs index 2cc6bc80c..f1437cb54 100644 --- a/eth2/types/src/attestation_data_and_custody_bit.rs +++ b/eth2/types/src/attestation_data_and_custody_bit.rs @@ -1,20 +1,22 @@ use super::AttestationData; use crate::test_utils::TestRandom; + use rand::RngCore; use serde_derive::Serialize; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Used for pairing an attestation with a proof-of-custody. /// -/// Spec v0.5.0 -#[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash)] +/// Spec v0.5.1 +#[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash, CachedTreeHash)] pub struct AttestationDataAndCustodyBit { pub data: AttestationData, pub custody_bit: bool, } -impl TestRandom for AttestationDataAndCustodyBit { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for AttestationDataAndCustodyBit { + fn random_for_test(rng: &mut impl RngCore) -> Self { Self { data: <_>::random_for_test(rng), custody_bit: <_>::random_for_test(rng), @@ -27,4 +29,5 @@ mod test { use super::*; ssz_tests!(AttestationDataAndCustodyBit); + cached_tree_hash_tests!(AttestationDataAndCustodyBit); } diff --git a/eth2/types/src/attester_slashing.rs b/eth2/types/src/attester_slashing.rs index 6fc404f42..d7b5d5942 100644 --- a/eth2/types/src/attester_slashing.rs +++ b/eth2/types/src/attester_slashing.rs @@ -1,13 +1,25 @@ use crate::{test_utils::TestRandom, SlashableAttestation}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Two conflicting attestations. /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct AttesterSlashing { pub slashable_attestation_1: SlashableAttestation, pub slashable_attestation_2: SlashableAttestation, @@ -18,4 +30,5 @@ mod tests { use super::*; ssz_tests!(AttesterSlashing); + cached_tree_hash_tests!(AttesterSlashing); } diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index 77c1620f3..33d73db16 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -1,15 +1,16 @@ use crate::test_utils::TestRandom; use crate::*; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// A block of the `BeaconChain`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, PartialEq, @@ -19,6 +20,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -34,7 +36,7 @@ pub struct BeaconBlock { impl BeaconBlock { /// Returns an empty block to be used during genesis. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn empty(spec: &ChainSpec) -> BeaconBlock { BeaconBlock { slot: spec.genesis_slot, @@ -57,11 +59,11 @@ impl BeaconBlock { } } - /// Returns the `hash_tree_root` of the block. + /// Returns the `tree_hash_root | update` of the block. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn canonical_root(&self) -> Hash256 { - Hash256::from_slice(&self.hash_tree_root()[..]) + Hash256::from_slice(&self.tree_hash_root()[..]) } /// Returns a full `BeaconBlockHeader` of this block. @@ -71,20 +73,20 @@ impl BeaconBlock { /// /// Note: performs a full tree-hash of `self.body`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn block_header(&self) -> BeaconBlockHeader { BeaconBlockHeader { slot: self.slot, previous_block_root: self.previous_block_root, state_root: self.state_root, - block_body_root: Hash256::from_slice(&self.body.hash_tree_root()[..]), + block_body_root: Hash256::from_slice(&self.body.tree_hash_root()[..]), signature: self.signature.clone(), } } /// Returns a "temporary" header, where the `state_root` is `spec.zero_hash`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn temporary_block_header(&self, spec: &ChainSpec) -> BeaconBlockHeader { BeaconBlockHeader { state_root: spec.zero_hash, @@ -99,4 +101,5 @@ mod tests { use super::*; ssz_tests!(BeaconBlock); + cached_tree_hash_tests!(BeaconBlock); } diff --git a/eth2/types/src/beacon_block_body.rs b/eth2/types/src/beacon_block_body.rs index 677e24cec..867db78c4 100644 --- a/eth2/types/src/beacon_block_body.rs +++ b/eth2/types/src/beacon_block_body.rs @@ -1,14 +1,26 @@ use crate::test_utils::TestRandom; use crate::*; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// The body of a `BeaconChain` block, containing operations. /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct BeaconBlockBody { pub randao_reveal: Signature, pub eth1_data: Eth1Data, @@ -25,4 +37,5 @@ mod tests { use super::*; ssz_tests!(BeaconBlockBody); + cached_tree_hash_tests!(BeaconBlockBody); } diff --git a/eth2/types/src/beacon_block_header.rs b/eth2/types/src/beacon_block_header.rs index 090d0a965..601346db5 100644 --- a/eth2/types/src/beacon_block_header.rs +++ b/eth2/types/src/beacon_block_header.rs @@ -1,15 +1,16 @@ use crate::test_utils::TestRandom; use crate::*; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::{SignedRoot, TreeHash}; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// A header of a `BeaconBlock`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, PartialEq, @@ -19,6 +20,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -32,16 +34,16 @@ pub struct BeaconBlockHeader { } impl BeaconBlockHeader { - /// Returns the `hash_tree_root` of the header. + /// Returns the `tree_hash_root` of the header. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn canonical_root(&self) -> Hash256 { - Hash256::from_slice(&self.hash_tree_root()[..]) + Hash256::from_slice(&self.signed_root()[..]) } /// Given a `body`, consumes `self` and returns a complete `BeaconBlock`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn into_block(self, body: BeaconBlockBody) -> BeaconBlock { BeaconBlock { slot: self.slot, @@ -58,4 +60,5 @@ mod tests { use super::*; ssz_tests!(BeaconBlockHeader); + cached_tree_hash_tests!(BeaconBlockHeader); } diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 774e8eb76..d8eade8bd 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -1,14 +1,22 @@ use self::epoch_cache::{get_active_validator_indices, EpochCache, Error as EpochCacheError}; use crate::test_utils::TestRandom; use crate::*; +use cached_tree_hash::{Error as TreeHashCacheError, TreeHashCache}; +use hashing::hash; use int_to_bytes::int_to_bytes32; use pubkey_cache::PubkeyCache; -use rand::RngCore; -use serde_derive::{Deserialize, Serialize}; -use ssz::{hash, ssz_encode, TreeHash}; -use ssz_derive::{Decode, Encode, TreeHash}; -use test_random_derive::TestRandom; +use fixed_len_vec::{typenum::Unsigned, FixedLenVec}; +use serde_derive::{Deserialize, Serialize}; +use ssz::ssz_encode; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, TreeHash}; + +pub use beacon_state_types::*; + +mod beacon_state_types; mod epoch_cache; mod pubkey_cache; mod tests; @@ -40,13 +48,28 @@ pub enum Error { EpochCacheUninitialized(RelativeEpoch), RelativeEpochError(RelativeEpochError), EpochCacheError(EpochCacheError), + TreeHashCacheError(TreeHashCacheError), } /// The state of the `BeaconChain` at some slot. /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, TestRandom, Encode, Decode, TreeHash)] -pub struct BeaconState { +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + TestRandom, + Encode, + Decode, + TreeHash, + CachedTreeHash, +)] +pub struct BeaconState +where + T: EthSpec, +{ // Misc pub slot: Slot, pub genesis_time: u64, @@ -58,7 +81,7 @@ pub struct BeaconState { pub validator_registry_update_epoch: Epoch, // Randomness and committees - pub latest_randao_mixes: Vec, + pub latest_randao_mixes: FixedLenVec, pub previous_shuffling_start_shard: u64, pub current_shuffling_start_shard: u64, pub previous_shuffling_epoch: Epoch, @@ -78,11 +101,11 @@ pub struct BeaconState { pub finalized_root: Hash256, // Recent state - pub latest_crosslinks: Vec, - latest_block_roots: Vec, - latest_state_roots: Vec, - latest_active_index_roots: Vec, - latest_slashed_balances: Vec, + pub latest_crosslinks: FixedLenVec, + pub latest_block_roots: FixedLenVec, + latest_state_roots: FixedLenVec, + latest_active_index_roots: FixedLenVec, + latest_slashed_balances: FixedLenVec, pub latest_block_header: BeaconBlockHeader, pub historical_roots: Vec, @@ -110,16 +133,26 @@ pub struct BeaconState { #[tree_hash(skip_hashing)] #[test_random(default)] pub pubkey_cache: PubkeyCache, + #[serde(skip_serializing, skip_deserializing)] + #[ssz(skip_serializing)] + #[ssz(skip_deserializing)] + #[tree_hash(skip_hashing)] + #[test_random(default)] + pub tree_hash_cache: TreeHashCache, } -impl BeaconState { +impl BeaconState { /// Produce the first state of the Beacon Chain. /// /// This does not fully build a genesis beacon state, it omits processing of initial validator /// deposits. To obtain a full genesis beacon state, use the `BeaconStateBuilder`. /// - /// Spec v0.5.0 - pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState { + /// Spec v0.5.1 + pub fn genesis( + genesis_time: u64, + latest_eth1_data: Eth1Data, + spec: &ChainSpec, + ) -> BeaconState { let initial_crosslink = Crosslink { epoch: spec.genesis_epoch, crosslink_data_root: spec.zero_hash, @@ -137,7 +170,10 @@ impl BeaconState { validator_registry_update_epoch: spec.genesis_epoch, // Randomness and committees - latest_randao_mixes: vec![spec.zero_hash; spec.latest_randao_mixes_length as usize], + latest_randao_mixes: FixedLenVec::from(vec![ + spec.zero_hash; + T::LatestRandaoMixesLength::to_usize() + ]), previous_shuffling_start_shard: spec.genesis_start_shard, current_shuffling_start_shard: spec.genesis_start_shard, previous_shuffling_epoch: spec.genesis_epoch, @@ -157,11 +193,22 @@ impl BeaconState { finalized_root: spec.zero_hash, // Recent state - latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize], - latest_block_roots: vec![spec.zero_hash; spec.slots_per_historical_root], - latest_state_roots: vec![spec.zero_hash; spec.slots_per_historical_root], - latest_active_index_roots: vec![spec.zero_hash; spec.latest_active_index_roots_length], - latest_slashed_balances: vec![0; spec.latest_slashed_exit_length], + latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize].into(), + latest_block_roots: FixedLenVec::from(vec![ + spec.zero_hash; + T::SlotsPerHistoricalRoot::to_usize() + ]), + latest_state_roots: FixedLenVec::from(vec![ + spec.zero_hash; + T::SlotsPerHistoricalRoot::to_usize() + ]), + latest_active_index_roots: FixedLenVec::from( + vec![spec.zero_hash; T::LatestActiveIndexRootsLength::to_usize()], + ), + latest_slashed_balances: FixedLenVec::from(vec![ + 0; + T::LatestSlashedExitLength::to_usize() + ]), latest_block_header: BeaconBlock::empty(spec).temporary_block_header(spec), historical_roots: vec![], @@ -183,17 +230,18 @@ impl BeaconState { EpochCache::default(), ], pubkey_cache: PubkeyCache::default(), + tree_hash_cache: TreeHashCache::default(), } } - /// Returns the `hash_tree_root` of the state. + /// Returns the `tree_hash_root` of the state. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn canonical_root(&self) -> Hash256 { - Hash256::from_slice(&self.hash_tree_root()[..]) + Hash256::from_slice(&self.tree_hash_root()[..]) } - pub fn historical_batch(&self) -> HistoricalBatch { + pub fn historical_batch(&self) -> HistoricalBatch { HistoricalBatch { block_roots: self.latest_block_roots.clone(), state_roots: self.latest_state_roots.clone(), @@ -217,7 +265,7 @@ impl BeaconState { /// The epoch corresponding to `self.slot`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn current_epoch(&self, spec: &ChainSpec) -> Epoch { self.slot.epoch(spec.slots_per_epoch) } @@ -226,14 +274,14 @@ impl BeaconState { /// /// If the current epoch is the genesis epoch, the genesis_epoch is returned. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn previous_epoch(&self, spec: &ChainSpec) -> Epoch { self.current_epoch(&spec) - 1 } /// The epoch following `self.current_epoch()`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn next_epoch(&self, spec: &ChainSpec) -> Epoch { self.current_epoch(spec) + 1 } @@ -246,7 +294,7 @@ impl BeaconState { /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_cached_active_validator_indices( &self, relative_epoch: RelativeEpoch, @@ -261,7 +309,7 @@ impl BeaconState { /// /// Does not utilize the cache, performs a full iteration over the validator registry. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec { get_active_validator_indices(&self.validator_registry, epoch) } @@ -270,7 +318,7 @@ impl BeaconState { /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_crosslink_committees_at_slot( &self, slot: Slot, @@ -295,7 +343,7 @@ impl BeaconState { /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_crosslink_committee_for_shard( &self, epoch: Epoch, @@ -321,7 +369,7 @@ impl BeaconState { /// /// If the state does not contain an index for a beacon proposer at the requested `slot`, then `None` is returned. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_beacon_proposer_index( &self, slot: Slot, @@ -350,15 +398,10 @@ impl BeaconState { /// Safely obtains the index for latest block roots, given some `slot`. /// - /// Spec v0.5.0 - fn get_latest_block_roots_index(&self, slot: Slot, spec: &ChainSpec) -> Result { - if (slot < self.slot) && (self.slot <= slot + spec.slots_per_historical_root as u64) { - let i = slot.as_usize() % spec.slots_per_historical_root; - if i >= self.latest_block_roots.len() { - Err(Error::InsufficientStateRoots) - } else { - Ok(i) - } + /// Spec v0.5.1 + fn get_latest_block_roots_index(&self, slot: Slot) -> Result { + if (slot < self.slot) && (self.slot <= slot + self.latest_block_roots.len() as u64) { + Ok(slot.as_usize() % self.latest_block_roots.len()) } else { Err(BeaconStateError::SlotOutOfBounds) } @@ -366,45 +409,34 @@ impl BeaconState { /// Return the block root at a recent `slot`. /// - /// Spec v0.5.0 - pub fn get_block_root( - &self, - slot: Slot, - spec: &ChainSpec, - ) -> Result<&Hash256, BeaconStateError> { - let i = self.get_latest_block_roots_index(slot, spec)?; + /// Spec v0.5.1 + pub fn get_block_root(&self, slot: Slot) -> Result<&Hash256, BeaconStateError> { + let i = self.get_latest_block_roots_index(slot)?; Ok(&self.latest_block_roots[i]) } /// Sets the block root for some given slot. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn set_block_root( &mut self, slot: Slot, block_root: Hash256, - spec: &ChainSpec, ) -> Result<(), BeaconStateError> { - let i = self.get_latest_block_roots_index(slot, spec)?; + let i = self.get_latest_block_roots_index(slot)?; self.latest_block_roots[i] = block_root; Ok(()) } /// Safely obtains the index for `latest_randao_mixes` /// - /// Spec v0.5.0 + /// Spec v0.5.1 fn get_randao_mix_index(&self, epoch: Epoch, spec: &ChainSpec) -> Result { let current_epoch = self.current_epoch(spec); + let len = T::LatestRandaoMixesLength::to_u64(); - if (current_epoch - (spec.latest_randao_mixes_length as u64) < epoch) - & (epoch <= current_epoch) - { - let i = epoch.as_usize() % spec.latest_randao_mixes_length; - if i < self.latest_randao_mixes.len() { - Ok(i) - } else { - Err(Error::InsufficientRandaoMixes) - } + if (current_epoch - len < epoch) & (epoch <= current_epoch) { + Ok(epoch.as_usize() % len as usize) } else { Err(Error::EpochOutOfBounds) } @@ -416,14 +448,14 @@ impl BeaconState { /// /// See `Self::get_randao_mix`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn update_randao_mix( &mut self, epoch: Epoch, signature: &Signature, spec: &ChainSpec, ) -> Result<(), Error> { - let i = epoch.as_usize() % spec.latest_randao_mixes_length; + let i = epoch.as_usize() % T::LatestRandaoMixesLength::to_usize(); let signature_hash = Hash256::from_slice(&hash(&ssz_encode(signature))); @@ -434,7 +466,7 @@ impl BeaconState { /// Return the randao mix at a recent ``epoch``. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_randao_mix(&self, epoch: Epoch, spec: &ChainSpec) -> Result<&Hash256, Error> { let i = self.get_randao_mix_index(epoch, spec)?; Ok(&self.latest_randao_mixes[i]) @@ -442,7 +474,7 @@ impl BeaconState { /// Set the randao mix at a recent ``epoch``. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn set_randao_mix( &mut self, epoch: Epoch, @@ -456,21 +488,16 @@ impl BeaconState { /// Safely obtains the index for `latest_active_index_roots`, given some `epoch`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 fn get_active_index_root_index(&self, epoch: Epoch, spec: &ChainSpec) -> Result { let current_epoch = self.current_epoch(spec); - if (current_epoch - spec.latest_active_index_roots_length as u64 + if (current_epoch - self.latest_active_index_roots.len() as u64 + spec.activation_exit_delay < epoch) & (epoch <= current_epoch + spec.activation_exit_delay) { - let i = epoch.as_usize() % spec.latest_active_index_roots_length; - if i < self.latest_active_index_roots.len() { - Ok(i) - } else { - Err(Error::InsufficientIndexRoots) - } + Ok(epoch.as_usize() % self.latest_active_index_roots.len()) } else { Err(Error::EpochOutOfBounds) } @@ -478,7 +505,7 @@ impl BeaconState { /// Return the `active_index_root` at a recent `epoch`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_active_index_root(&self, epoch: Epoch, spec: &ChainSpec) -> Result { let i = self.get_active_index_root_index(epoch, spec)?; Ok(self.latest_active_index_roots[i]) @@ -486,7 +513,7 @@ impl BeaconState { /// Set the `active_index_root` at a recent `epoch`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn set_active_index_root( &mut self, epoch: Epoch, @@ -500,23 +527,18 @@ impl BeaconState { /// Replace `active_index_roots` with clones of `index_root`. /// - /// Spec v0.5.0 - pub fn fill_active_index_roots_with(&mut self, index_root: Hash256, spec: &ChainSpec) { + /// Spec v0.5.1 + pub fn fill_active_index_roots_with(&mut self, index_root: Hash256) { self.latest_active_index_roots = - vec![index_root; spec.latest_active_index_roots_length as usize] + vec![index_root; self.latest_active_index_roots.len() as usize].into() } /// Safely obtains the index for latest state roots, given some `slot`. /// - /// Spec v0.5.0 - fn get_latest_state_roots_index(&self, slot: Slot, spec: &ChainSpec) -> Result { - if (slot < self.slot) && (self.slot <= slot + spec.slots_per_historical_root as u64) { - let i = slot.as_usize() % spec.slots_per_historical_root; - if i >= self.latest_state_roots.len() { - Err(Error::InsufficientStateRoots) - } else { - Ok(i) - } + /// Spec v0.5.1 + fn get_latest_state_roots_index(&self, slot: Slot) -> Result { + if (slot < self.slot) && (self.slot <= slot + self.latest_state_roots.len() as u64) { + Ok(slot.as_usize() % self.latest_state_roots.len()) } else { Err(BeaconStateError::SlotOutOfBounds) } @@ -524,31 +546,26 @@ impl BeaconState { /// Gets the state root for some slot. /// - /// Spec v0.5.0 - pub fn get_state_root(&mut self, slot: Slot, spec: &ChainSpec) -> Result<&Hash256, Error> { - let i = self.get_latest_state_roots_index(slot, spec)?; + /// Spec v0.5.1 + pub fn get_state_root(&mut self, slot: Slot) -> Result<&Hash256, Error> { + let i = self.get_latest_state_roots_index(slot)?; Ok(&self.latest_state_roots[i]) } /// Sets the latest state root for slot. /// - /// Spec v0.5.0 - pub fn set_state_root( - &mut self, - slot: Slot, - state_root: Hash256, - spec: &ChainSpec, - ) -> Result<(), Error> { - let i = self.get_latest_state_roots_index(slot, spec)?; + /// Spec v0.5.1 + pub fn set_state_root(&mut self, slot: Slot, state_root: Hash256) -> Result<(), Error> { + let i = self.get_latest_state_roots_index(slot)?; self.latest_state_roots[i] = state_root; Ok(()) } /// Safely obtains the index for `latest_slashed_balances`, given some `epoch`. /// - /// Spec v0.5.0 - fn get_slashed_balance_index(&self, epoch: Epoch, spec: &ChainSpec) -> Result { - let i = epoch.as_usize() % spec.latest_slashed_exit_length; + /// Spec v0.5.1 + fn get_slashed_balance_index(&self, epoch: Epoch) -> Result { + let i = epoch.as_usize() % self.latest_slashed_balances.len(); // NOTE: the validity of the epoch is not checked. It is not in the spec but it's probably // useful to have. @@ -561,29 +578,24 @@ impl BeaconState { /// Gets the total slashed balances for some epoch. /// - /// Spec v0.5.0 - pub fn get_slashed_balance(&self, epoch: Epoch, spec: &ChainSpec) -> Result { - let i = self.get_slashed_balance_index(epoch, spec)?; + /// Spec v0.5.1 + pub fn get_slashed_balance(&self, epoch: Epoch) -> Result { + let i = self.get_slashed_balance_index(epoch)?; Ok(self.latest_slashed_balances[i]) } /// Sets the total slashed balances for some epoch. /// - /// Spec v0.5.0 - pub fn set_slashed_balance( - &mut self, - epoch: Epoch, - balance: u64, - spec: &ChainSpec, - ) -> Result<(), Error> { - let i = self.get_slashed_balance_index(epoch, spec)?; + /// Spec v0.5.1 + pub fn set_slashed_balance(&mut self, epoch: Epoch, balance: u64) -> Result<(), Error> { + let i = self.get_slashed_balance_index(epoch)?; self.latest_slashed_balances[i] = balance; Ok(()) } /// Generate a seed for the given `epoch`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn generate_seed(&self, epoch: Epoch, spec: &ChainSpec) -> Result { let mut input = self .get_randao_mix(epoch - spec.min_seed_lookahead, spec)? @@ -599,7 +611,7 @@ impl BeaconState { /// Return the effective balance (also known as "balance at stake") for a validator with the given ``index``. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_effective_balance( &self, validator_index: usize, @@ -614,14 +626,14 @@ impl BeaconState { /// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_delayed_activation_exit_epoch(&self, epoch: Epoch, spec: &ChainSpec) -> Epoch { epoch + 1 + spec.activation_exit_delay } /// Initiate an exit for the validator of the given `index`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn initiate_validator_exit(&mut self, validator_index: usize) { self.validator_registry[validator_index].initiated_exit = true; } @@ -633,7 +645,7 @@ impl BeaconState { /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_attestation_duties( &self, validator_index: usize, @@ -649,7 +661,7 @@ impl BeaconState { /// Return the combined effective balance of an array of validators. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_total_balance( &self, validator_indices: &[usize], @@ -668,6 +680,7 @@ impl BeaconState { self.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, spec)?; self.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, spec)?; self.update_pubkey_cache()?; + self.update_tree_hash_cache()?; Ok(()) } @@ -774,6 +787,39 @@ impl BeaconState { pub fn drop_pubkey_cache(&mut self) { self.pubkey_cache = PubkeyCache::default() } + + /// Update the tree hash cache, building it for the first time if it is empty. + /// + /// Returns the `tree_hash_root` resulting from the update. This root can be considered the + /// canonical root of `self`. + pub fn update_tree_hash_cache(&mut self) -> Result { + if self.tree_hash_cache.is_empty() { + self.tree_hash_cache = TreeHashCache::new(self)?; + } else { + // Move the cache outside of `self` to satisfy the borrow checker. + let mut cache = std::mem::replace(&mut self.tree_hash_cache, TreeHashCache::default()); + + cache.update(self)?; + + // Move the updated cache back into `self`. + self.tree_hash_cache = cache + } + + self.cached_tree_hash_root() + } + + /// Returns the tree hash root determined by the last execution of `self.update_tree_hash_cache(..)`. + /// + /// Note: does _not_ update the cache and may return an outdated root. + /// + /// Returns an error if the cache is not initialized or if an error is encountered during the + /// cache update. + pub fn cached_tree_hash_root(&self) -> Result { + self.tree_hash_cache + .tree_hash_root() + .and_then(|b| Ok(Hash256::from_slice(b))) + .map_err(Into::into) + } } impl From for Error { @@ -787,3 +833,9 @@ impl From for Error { Error::EpochCacheError(e) } } + +impl From for Error { + fn from(e: TreeHashCacheError) -> Error { + Error::TreeHashCacheError(e) + } +} diff --git a/eth2/types/src/beacon_state/beacon_state_types.rs b/eth2/types/src/beacon_state/beacon_state_types.rs new file mode 100644 index 000000000..b6c943a36 --- /dev/null +++ b/eth2/types/src/beacon_state/beacon_state_types.rs @@ -0,0 +1,111 @@ +use crate::*; +use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192}; +use serde_derive::{Deserialize, Serialize}; +use std::fmt::Debug; + +pub trait EthSpec: + 'static + Default + Sync + Send + Clone + Debug + PartialEq + serde::de::DeserializeOwned +{ + type ShardCount: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type LatestSlashedExitLength: Unsigned + Clone + Sync + Send + Debug + PartialEq; + + fn spec() -> ChainSpec; + + /// Returns the `SHARD_COUNT` constant for this specification. + /// + /// Spec v0.5.1 + fn shard_count() -> usize { + Self::ShardCount::to_usize() + } + + /// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification. + /// + /// Spec v0.5.1 + fn slots_per_historical_root() -> usize { + Self::SlotsPerHistoricalRoot::to_usize() + } + + /// Returns the `LATEST_RANDAO_MIXES_LENGTH` constant for this specification. + /// + /// Spec v0.5.1 + fn latest_randao_mixes_length() -> usize { + Self::LatestRandaoMixesLength::to_usize() + } + + /// Returns the `LATEST_ACTIVE_INDEX_ROOTS` constant for this specification. + /// + /// Spec v0.5.1 + fn latest_active_index_roots() -> usize { + Self::LatestActiveIndexRootsLength::to_usize() + } + + /// Returns the `LATEST_SLASHED_EXIT_LENGTH` constant for this specification. + /// + /// Spec v0.5.1 + fn latest_slashed_exit_length() -> usize { + Self::LatestSlashedExitLength::to_usize() + } +} + +/// Ethereum Foundation specifications. +/// +/// Spec v0.5.1 +#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)] +pub struct FoundationEthSpec; + +impl EthSpec for FoundationEthSpec { + type ShardCount = U1024; + type SlotsPerHistoricalRoot = U8192; + type LatestRandaoMixesLength = U8192; + type LatestActiveIndexRootsLength = U8192; + type LatestSlashedExitLength = U8192; + + fn spec() -> ChainSpec { + ChainSpec::foundation() + } +} + +pub type FoundationBeaconState = BeaconState; + +/// Ethereum Foundation specifications, modified to be suitable for < 1000 validators. +/// +/// Spec v0.5.1 +#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)] +pub struct FewValidatorsEthSpec; + +impl EthSpec for FewValidatorsEthSpec { + type ShardCount = U8; + type SlotsPerHistoricalRoot = U8192; + type LatestRandaoMixesLength = U8192; + type LatestActiveIndexRootsLength = U8192; + type LatestSlashedExitLength = U8192; + + fn spec() -> ChainSpec { + ChainSpec::few_validators() + } +} + +pub type FewValidatorsBeaconState = BeaconState; + +/// Specifications suitable for a small-scale (< 1000 validators) lighthouse testnet. +/// +/// Spec v0.5.1 +#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)] +pub struct LighthouseTestnetEthSpec; + +impl EthSpec for LighthouseTestnetEthSpec { + type ShardCount = U8; + type SlotsPerHistoricalRoot = U8192; + type LatestRandaoMixesLength = U8192; + type LatestActiveIndexRootsLength = U8192; + type LatestSlashedExitLength = U8192; + + fn spec() -> ChainSpec { + ChainSpec::lighthouse_testnet() + } +} + +pub type LighthouseTestnetBeaconState = BeaconState; diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index 62df90271..c76c71684 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -28,8 +28,8 @@ pub struct EpochCache { impl EpochCache { /// Return a new, fully initialized cache. - pub fn initialized( - state: &BeaconState, + pub fn initialized( + state: &BeaconState, relative_epoch: RelativeEpoch, spec: &ChainSpec, ) -> Result { @@ -138,7 +138,7 @@ impl EpochCache { /// Returns a list of all `validator_registry` indices where the validator is active at the given /// `epoch`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec { let mut active = Vec::with_capacity(validators.len()); @@ -200,8 +200,8 @@ pub struct EpochCrosslinkCommitteesBuilder { impl EpochCrosslinkCommitteesBuilder { /// Instantiates a builder that will build for the `state`'s previous epoch. - pub fn for_previous_epoch( - state: &BeaconState, + pub fn for_previous_epoch( + state: &BeaconState, active_validator_indices: Vec, spec: &ChainSpec, ) -> Self { @@ -215,8 +215,8 @@ impl EpochCrosslinkCommitteesBuilder { } /// Instantiates a builder that will build for the `state`'s next epoch. - pub fn for_current_epoch( - state: &BeaconState, + pub fn for_current_epoch( + state: &BeaconState, active_validator_indices: Vec, spec: &ChainSpec, ) -> Self { @@ -233,8 +233,8 @@ impl EpochCrosslinkCommitteesBuilder { /// /// Note: there are two possible epoch builds for the next epoch, one where there is a registry /// change and one where there is not. - pub fn for_next_epoch( - state: &BeaconState, + pub fn for_next_epoch( + state: &BeaconState, active_validator_indices: Vec, registry_change: bool, spec: &ChainSpec, @@ -288,7 +288,7 @@ impl EpochCrosslinkCommitteesBuilder { self.active_validator_indices, spec.shuffle_round_count, &self.shuffling_seed[..], - true, + false, ) .ok_or_else(|| Error::UnableToShuffle)? }; diff --git a/eth2/types/src/beacon_state/epoch_cache/tests.rs b/eth2/types/src/beacon_state/epoch_cache/tests.rs index 5643776e2..2a3034192 100644 --- a/eth2/types/src/beacon_state/epoch_cache/tests.rs +++ b/eth2/types/src/beacon_state/epoch_cache/tests.rs @@ -1,11 +1,12 @@ #![cfg(test)] use super::*; +use crate::beacon_state::FewValidatorsEthSpec; use crate::test_utils::*; use swap_or_not_shuffle::shuffle_list; -fn do_sane_cache_test( - state: BeaconState, +fn do_sane_cache_test( + state: BeaconState, epoch: Epoch, relative_epoch: RelativeEpoch, validator_count: usize, @@ -27,7 +28,7 @@ fn do_sane_cache_test( active_indices, spec.shuffle_round_count, &expected_seed[..], - true, + false, ) .unwrap(); @@ -64,7 +65,7 @@ fn do_sane_cache_test( } } -fn setup_sane_cache_test(validator_count: usize, spec: &ChainSpec) -> BeaconState { +fn setup_sane_cache_test(validator_count: usize, spec: &ChainSpec) -> BeaconState { let mut builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, spec); @@ -98,10 +99,13 @@ fn setup_sane_cache_test(validator_count: usize, spec: &ChainSpec) -> BeaconStat #[test] fn builds_sane_current_epoch_cache() { - let mut spec = ChainSpec::few_validators(); + let mut spec = FewValidatorsEthSpec::spec(); spec.shard_count = 4; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let state = setup_sane_cache_test(validator_count as usize, &spec); + + let state: BeaconState = + setup_sane_cache_test(validator_count as usize, &spec); + do_sane_cache_test( state.clone(), state.current_epoch(&spec), @@ -115,10 +119,13 @@ fn builds_sane_current_epoch_cache() { #[test] fn builds_sane_previous_epoch_cache() { - let mut spec = ChainSpec::few_validators(); + let mut spec = FewValidatorsEthSpec::spec(); spec.shard_count = 2; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let state = setup_sane_cache_test(validator_count as usize, &spec); + + let state: BeaconState = + setup_sane_cache_test(validator_count as usize, &spec); + do_sane_cache_test( state.clone(), state.previous_epoch(&spec), @@ -132,10 +139,13 @@ fn builds_sane_previous_epoch_cache() { #[test] fn builds_sane_next_without_update_epoch_cache() { - let mut spec = ChainSpec::few_validators(); + let mut spec = FewValidatorsEthSpec::spec(); spec.shard_count = 2; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let mut state = setup_sane_cache_test(validator_count as usize, &spec); + + let mut state: BeaconState = + setup_sane_cache_test(validator_count as usize, &spec); + state.validator_registry_update_epoch = state.slot.epoch(spec.slots_per_epoch); do_sane_cache_test( state.clone(), diff --git a/eth2/types/src/beacon_state/tests.rs b/eth2/types/src/beacon_state/tests.rs index dc16a013b..aa3c0b98a 100644 --- a/eth2/types/src/beacon_state/tests.rs +++ b/eth2/types/src/beacon_state/tests.rs @@ -1,16 +1,18 @@ #![cfg(test)] use super::*; +use crate::beacon_state::FewValidatorsEthSpec; use crate::test_utils::*; -ssz_tests!(BeaconState); +ssz_tests!(FoundationBeaconState); +cached_tree_hash_tests!(FoundationBeaconState); /// Test that /// /// 1. Using the cache before it's built fails. /// 2. Using the cache after it's build passes. /// 3. Using the cache after it's dropped fails. -fn test_cache_initialization<'a>( - state: &'a mut BeaconState, +fn test_cache_initialization<'a, T: EthSpec>( + state: &'a mut BeaconState, relative_epoch: RelativeEpoch, spec: &ChainSpec, ) { @@ -44,9 +46,11 @@ fn test_cache_initialization<'a>( #[test] fn cache_initialization() { - let spec = ChainSpec::few_validators(); - let (mut state, _keypairs) = - TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec).build(); + let spec = FewValidatorsEthSpec::spec(); + + let builder: TestingBeaconStateBuilder = + TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec); + let (mut state, _keypairs) = builder.build(); state.slot = (spec.genesis_epoch + 1).start_slot(spec.slots_per_epoch); @@ -55,3 +59,22 @@ fn cache_initialization() { test_cache_initialization(&mut state, RelativeEpoch::NextWithRegistryChange, &spec); test_cache_initialization(&mut state, RelativeEpoch::NextWithoutRegistryChange, &spec); } + +#[test] +fn tree_hash_cache() { + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use tree_hash::TreeHash; + + let mut rng = XorShiftRng::from_seed([42; 16]); + + let mut state: FoundationBeaconState = BeaconState::random_for_test(&mut rng); + + let root = state.update_tree_hash_cache().unwrap(); + + assert_eq!(root.as_bytes(), &state.tree_hash_root()[..]); + + state.slot = state.slot + 1; + + let root = state.update_tree_hash_cache().unwrap(); + assert_eq!(root.as_bytes(), &state.tree_hash_root()[..]); +} diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index 0042304f8..974bcfc4a 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -8,7 +8,7 @@ const GWEI: u64 = 1_000_000_000; /// Each of the BLS signature domains. /// -/// Spec v0.5.0 +/// Spec v0.5.1 pub enum Domain { BeaconBlock, Randao, @@ -20,7 +20,7 @@ pub enum Domain { /// Holds all the "constants" for a BeaconChain. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive(PartialEq, Debug, Clone, Deserialize)] #[serde(default)] pub struct ChainSpec { @@ -70,17 +70,9 @@ pub struct ChainSpec { pub min_seed_lookahead: Epoch, pub activation_exit_delay: u64, pub epochs_per_eth1_voting_period: u64, - pub slots_per_historical_root: usize, pub min_validator_withdrawability_delay: Epoch, pub persistent_committee_period: u64, - /* - * State list lengths - */ - pub latest_randao_mixes_length: usize, - pub latest_active_index_roots_length: usize, - pub latest_slashed_exit_length: usize, - /* * Reward and penalty quotients */ @@ -126,7 +118,7 @@ pub struct ChainSpec { impl ChainSpec { /// Return the number of committees in one epoch. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_epoch_committee_count(&self, active_validator_count: usize) -> u64 { std::cmp::max( 1, @@ -139,7 +131,7 @@ impl ChainSpec { /// Get the domain number that represents the fork meta and signature domain. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 { let domain_constant = match domain { Domain::BeaconBlock => self.domain_beacon_block, @@ -161,8 +153,8 @@ impl ChainSpec { /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification. /// - /// Spec v0.5.0 - pub fn foundation() -> Self { + /// Spec v0.5.1 + pub(crate) fn foundation() -> Self { let genesis_slot = Slot::new(2_u64.pow(32)); let slots_per_epoch = 64; let genesis_epoch = genesis_slot.epoch(slots_per_epoch); @@ -213,17 +205,9 @@ impl ChainSpec { min_seed_lookahead: Epoch::new(1), activation_exit_delay: 4, epochs_per_eth1_voting_period: 16, - slots_per_historical_root: 8_192, min_validator_withdrawability_delay: Epoch::new(256), persistent_committee_period: 2_048, - /* - * State list lengths - */ - latest_randao_mixes_length: 8_192, - latest_active_index_roots_length: 8_192, - latest_slashed_exit_length: 8_192, - /* * Reward and penalty quotients */ @@ -264,7 +248,7 @@ impl ChainSpec { /// Returns a `ChainSpec` compatible with the Lighthouse testnet specification. /// /// Spec v0.4.0 - pub fn lighthouse_testnet() -> Self { + pub(crate) fn lighthouse_testnet() -> Self { /* * Lighthouse testnet bootnodes */ @@ -280,7 +264,7 @@ impl ChainSpec { } /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators. - pub fn few_validators() -> Self { + pub(crate) fn few_validators() -> Self { let genesis_slot = Slot::new(2_u64.pow(32)); let slots_per_epoch = 8; let genesis_epoch = genesis_slot.epoch(slots_per_epoch); diff --git a/eth2/types/src/crosslink.rs b/eth2/types/src/crosslink.rs index f91680c75..cb3ce5615 100644 --- a/eth2/types/src/crosslink.rs +++ b/eth2/types/src/crosslink.rs @@ -1,13 +1,14 @@ use crate::test_utils::TestRandom; use crate::{Epoch, Hash256}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Specifies the block hash for a shard at an epoch. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, Clone, @@ -19,6 +20,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, )] pub struct Crosslink { @@ -31,4 +33,5 @@ mod tests { use super::*; ssz_tests!(Crosslink); + cached_tree_hash_tests!(Crosslink); } diff --git a/eth2/types/src/crosslink_committee.rs b/eth2/types/src/crosslink_committee.rs index af1778a1b..25c42c07b 100644 --- a/eth2/types/src/crosslink_committee.rs +++ b/eth2/types/src/crosslink_committee.rs @@ -1,8 +1,20 @@ use crate::*; use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; +use tree_hash_derive::{CachedTreeHash, TreeHash}; -#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize, Decode, Encode, TreeHash)] +#[derive( + Default, + Clone, + Debug, + PartialEq, + Serialize, + Deserialize, + Decode, + Encode, + TreeHash, + CachedTreeHash, +)] pub struct CrosslinkCommittee { pub slot: Slot, pub shard: Shard, diff --git a/eth2/types/src/deposit.rs b/eth2/types/src/deposit.rs index ff8d83d77..67ceea5be 100644 --- a/eth2/types/src/deposit.rs +++ b/eth2/types/src/deposit.rs @@ -1,16 +1,29 @@ -use super::{DepositData, Hash256}; use crate::test_utils::TestRandom; -use rand::RngCore; +use crate::*; +use fixed_len_vec::typenum::U32; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// A deposit to potentially become a beacon chain validator. /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct Deposit { - pub proof: Vec, + pub proof: FixedLenVec, pub index: u64, pub deposit_data: DepositData, } @@ -20,4 +33,5 @@ mod tests { use super::*; ssz_tests!(Deposit); + cached_tree_hash_tests!(Deposit); } diff --git a/eth2/types/src/deposit_data.rs b/eth2/types/src/deposit_data.rs index a1e30032f..bee1d503e 100644 --- a/eth2/types/src/deposit_data.rs +++ b/eth2/types/src/deposit_data.rs @@ -1,14 +1,26 @@ use super::DepositInput; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Data generated by the deposit contract. /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct DepositData { pub amount: u64, pub timestamp: u64, @@ -20,4 +32,5 @@ mod tests { use super::*; ssz_tests!(DepositData); + cached_tree_hash_tests!(DepositData); } diff --git a/eth2/types/src/deposit_input.rs b/eth2/types/src/deposit_input.rs index 380528dc0..f44c75f5a 100644 --- a/eth2/types/src/deposit_input.rs +++ b/eth2/types/src/deposit_input.rs @@ -1,15 +1,16 @@ use crate::test_utils::TestRandom; use crate::*; use bls::{PublicKey, Signature}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::{SignedRoot, TreeHash}; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::{SignedRoot, TreeHash}; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// The data supplied by the user to the deposit contract. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, PartialEq, @@ -20,6 +21,7 @@ use test_random_derive::TestRandom; Decode, SignedRoot, TreeHash, + CachedTreeHash, TestRandom, )] pub struct DepositInput { @@ -32,7 +34,7 @@ pub struct DepositInput { impl DepositInput { /// Generate the 'proof_of_posession' signature for a given DepositInput details. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn create_proof_of_possession( &self, secret_key: &SecretKey, @@ -48,7 +50,7 @@ impl DepositInput { /// Verify that proof-of-possession is valid. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn validate_proof_of_possession( &self, epoch: Epoch, @@ -67,6 +69,7 @@ mod tests { use super::*; ssz_tests!(DepositInput); + cached_tree_hash_tests!(DepositInput); #[test] fn can_create_and_validate() { diff --git a/eth2/types/src/epoch_cache.rs b/eth2/types/src/epoch_cache.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/eth2/types/src/eth1_data.rs b/eth2/types/src/eth1_data.rs index deced19fb..aaf5bca54 100644 --- a/eth2/types/src/eth1_data.rs +++ b/eth2/types/src/eth1_data.rs @@ -1,15 +1,26 @@ use super::Hash256; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Contains data obtained from the Eth1 chain. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( - Debug, PartialEq, Clone, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, + Debug, + PartialEq, + Clone, + Default, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, )] pub struct Eth1Data { pub deposit_root: Hash256, @@ -21,4 +32,5 @@ mod tests { use super::*; ssz_tests!(Eth1Data); + cached_tree_hash_tests!(Eth1Data); } diff --git a/eth2/types/src/eth1_data_vote.rs b/eth2/types/src/eth1_data_vote.rs index 2f3a1ade1..27cb0be78 100644 --- a/eth2/types/src/eth1_data_vote.rs +++ b/eth2/types/src/eth1_data_vote.rs @@ -1,15 +1,26 @@ use super::Eth1Data; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// A summation of votes for some `Eth1Data`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( - Debug, PartialEq, Clone, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, + Debug, + PartialEq, + Clone, + Default, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, )] pub struct Eth1DataVote { pub eth1_data: Eth1Data, @@ -21,4 +32,5 @@ mod tests { use super::*; ssz_tests!(Eth1DataVote); + cached_tree_hash_tests!(Eth1DataVote); } diff --git a/eth2/types/src/fork.rs b/eth2/types/src/fork.rs index b9d16c333..3e7254dd3 100644 --- a/eth2/types/src/fork.rs +++ b/eth2/types/src/fork.rs @@ -3,16 +3,27 @@ use crate::{ ChainSpec, Epoch, }; use int_to_bytes::int_to_bytes4; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Specifies a fork of the `BeaconChain`, to prevent replay attacks. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( - Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, + Debug, + Clone, + PartialEq, + Default, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, )] pub struct Fork { #[serde(deserialize_with = "fork_from_hex_str")] @@ -25,7 +36,7 @@ pub struct Fork { impl Fork { /// Initialize the `Fork` from the genesis parameters in the `spec`. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn genesis(spec: &ChainSpec) -> Self { let mut current_version: [u8; 4] = [0; 4]; current_version.copy_from_slice(&int_to_bytes4(spec.genesis_fork_version)); @@ -39,7 +50,7 @@ impl Fork { /// Return the fork version of the given ``epoch``. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn get_fork_version(&self, epoch: Epoch) -> [u8; 4] { if epoch < self.epoch { return self.previous_version; @@ -53,6 +64,7 @@ mod tests { use super::*; ssz_tests!(Fork); + cached_tree_hash_tests!(Fork); fn test_genesis(version: u32, epoch: Epoch) { let mut spec = ChainSpec::foundation(); diff --git a/eth2/types/src/historical_batch.rs b/eth2/types/src/historical_batch.rs index 77859ed1a..d80838221 100644 --- a/eth2/types/src/historical_batch.rs +++ b/eth2/types/src/historical_batch.rs @@ -1,22 +1,38 @@ use crate::test_utils::TestRandom; -use crate::Hash256; -use rand::RngCore; +use crate::*; + +use fixed_len_vec::FixedLenVec; use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Historical block and state roots. /// -/// Spec v0.5.0 -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] -pub struct HistoricalBatch { - pub block_roots: Vec, - pub state_roots: Vec, +/// Spec v0.5.1 +#[derive( + Debug, + Clone, + PartialEq, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] +pub struct HistoricalBatch { + pub block_roots: FixedLenVec, + pub state_roots: FixedLenVec, } #[cfg(test)] mod tests { use super::*; - ssz_tests!(HistoricalBatch); + pub type FoundationHistoricalBatch = HistoricalBatch; + + ssz_tests!(FoundationHistoricalBatch); + cached_tree_hash_tests!(FoundationHistoricalBatch); } diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 118e862e8..79981c890 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -46,7 +46,7 @@ pub use crate::attester_slashing::AttesterSlashing; pub use crate::beacon_block::BeaconBlock; pub use crate::beacon_block_body::BeaconBlockBody; pub use crate::beacon_block_header::BeaconBlockHeader; -pub use crate::beacon_state::{BeaconState, Error as BeaconStateError}; +pub use crate::beacon_state::{Error as BeaconStateError, *}; pub use crate::chain_spec::{ChainSpec, Domain}; pub use crate::crosslink::Crosslink; pub use crate::crosslink_committee::CrosslinkCommittee; @@ -85,6 +85,7 @@ pub type AttesterMap = HashMap<(u64, u64), Vec>; pub type ProposerMap = HashMap; pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, SecretKey, Signature}; +pub use fixed_len_vec::{typenum::Unsigned, FixedLenVec}; pub use libp2p::floodsub::{Topic, TopicBuilder, TopicHash}; pub use libp2p::multiaddr; pub use libp2p::Multiaddr; diff --git a/eth2/types/src/pending_attestation.rs b/eth2/types/src/pending_attestation.rs index 938e59bef..b158f1274 100644 --- a/eth2/types/src/pending_attestation.rs +++ b/eth2/types/src/pending_attestation.rs @@ -1,14 +1,26 @@ use crate::test_utils::TestRandom; use crate::{Attestation, AttestationData, Bitfield, Slot}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// An attestation that has been included in the state but not yet fully processed. /// -/// Spec v0.5.0 -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + Clone, + PartialEq, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct PendingAttestation { pub aggregation_bitfield: Bitfield, pub data: AttestationData, @@ -33,4 +45,5 @@ mod tests { use super::*; ssz_tests!(PendingAttestation); + cached_tree_hash_tests!(PendingAttestation); } diff --git a/eth2/types/src/proposer_slashing.rs b/eth2/types/src/proposer_slashing.rs index 02216a2fc..0c419dd56 100644 --- a/eth2/types/src/proposer_slashing.rs +++ b/eth2/types/src/proposer_slashing.rs @@ -1,14 +1,26 @@ use super::BeaconBlockHeader; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Two conflicting proposals from the same proposer (validator). /// -/// Spec v0.5.0 -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] +/// Spec v0.5.1 +#[derive( + Debug, + PartialEq, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + CachedTreeHash, + TestRandom, +)] pub struct ProposerSlashing { pub proposer_index: u64, pub header_1: BeaconBlockHeader, @@ -20,4 +32,5 @@ mod tests { use super::*; ssz_tests!(ProposerSlashing); + cached_tree_hash_tests!(ProposerSlashing); } diff --git a/eth2/types/src/relative_epoch.rs b/eth2/types/src/relative_epoch.rs index 8f895e97a..6538ca4aa 100644 --- a/eth2/types/src/relative_epoch.rs +++ b/eth2/types/src/relative_epoch.rs @@ -10,7 +10,7 @@ pub enum Error { /// Defines the epochs relative to some epoch. Most useful when referring to the committees prior /// to and following some epoch. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive(Debug, PartialEq, Clone, Copy)] pub enum RelativeEpoch { /// The prior epoch. @@ -32,7 +32,7 @@ pub enum RelativeEpoch { impl RelativeEpoch { /// Returns the `epoch` that `self` refers to, with respect to the `base` epoch. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn into_epoch(self, base: Epoch) -> Epoch { match self { RelativeEpoch::Previous => base - 1, @@ -51,7 +51,7 @@ impl RelativeEpoch { /// - `AmbiguiousNextEpoch` whenever `other` is one after `base`, because it's unknowable if /// there will be a registry change. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn from_epoch(base: Epoch, other: Epoch) -> Result { if other == base - 1 { Ok(RelativeEpoch::Previous) diff --git a/eth2/types/src/slashable_attestation.rs b/eth2/types/src/slashable_attestation.rs index e557285b8..19d9a87b6 100644 --- a/eth2/types/src/slashable_attestation.rs +++ b/eth2/types/src/slashable_attestation.rs @@ -1,15 +1,16 @@ use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, Bitfield, ChainSpec}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// Details an attestation that can be slashable. /// /// To be included in an `AttesterSlashing`. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, PartialEq, @@ -19,6 +20,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -34,14 +36,14 @@ pub struct SlashableAttestation { impl SlashableAttestation { /// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn is_double_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { self.data.slot.epoch(spec.slots_per_epoch) == other.data.slot.epoch(spec.slots_per_epoch) } /// Check if ``attestation_data_1`` surrounds ``attestation_data_2``. /// - /// Spec v0.5.0 + /// Spec v0.5.1 pub fn is_surround_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { let source_epoch_1 = self.data.source_epoch; let source_epoch_2 = other.data.source_epoch; @@ -132,6 +134,7 @@ mod tests { } ssz_tests!(SlashableAttestation); + cached_tree_hash_tests!(SlashableAttestation); fn create_slashable_attestation( slot_factor: u64, diff --git a/eth2/types/src/slot_epoch.rs b/eth2/types/src/slot_epoch.rs index d334177e5..b0f4bdcf9 100644 --- a/eth2/types/src/slot_epoch.rs +++ b/eth2/types/src/slot_epoch.rs @@ -1,20 +1,21 @@ +//! The `Slot` and `Epoch` types are defined as newtypes over u64 to enforce type-safety between +//! the two types. +//! +//! `Slot` and `Epoch` have implementations which permit conversion, comparison and math operations +//! between each and `u64`, however specifically not between each other. +//! +//! All math operations on `Slot` and `Epoch` are saturating, they never wrap. +//! +//! It would be easy to define `PartialOrd` and other traits generically across all types which +//! implement `Into`, however this would allow operations between `Slots` and `Epochs` which +//! may lead to programming errors which are not detected by the compiler. + use crate::slot_height::SlotHeight; -/// The `Slot` and `Epoch` types are defined as newtypes over u64 to enforce type-safety between -/// the two types. -/// -/// `Slot` and `Epoch` have implementations which permit conversion, comparison and math operations -/// between each and `u64`, however specifically not between each other. -/// -/// All math operations on `Slot` and `Epoch` are saturating, they never wrap. -/// -/// It would be easy to define `PartialOrd` and other traits generically across all types which -/// implement `Into`, however this would allow operations between `Slots` and `Epochs` which -/// may lead to programming errors which are not detected by the compiler. use crate::test_utils::TestRandom; use rand::RngCore; use serde_derive::{Deserialize, Serialize}; use slog; -use ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError, Encode}; use std::cmp::{Ord, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -144,11 +145,13 @@ mod epoch_tests { #[test] fn max_epoch_ssz() { let max_epoch = Epoch::max_value(); - let mut ssz = SszStream::new(); - ssz.append(&max_epoch); - let encoded = ssz.drain(); - assert_eq!(&encoded, &[255, 255, 255, 255, 255, 255, 255, 255]); - let (decoded, _i): (Epoch, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); - assert_eq!(max_epoch, decoded); + assert_eq!( + &max_epoch.as_ssz_bytes(), + &[255, 255, 255, 255, 255, 255, 255, 255] + ); + assert_eq!( + max_epoch, + Epoch::from_ssz_bytes(&max_epoch.as_ssz_bytes()).unwrap() + ); } } diff --git a/eth2/types/src/slot_epoch_macros.rs b/eth2/types/src/slot_epoch_macros.rs index 300ad3f6f..1e24f8e99 100644 --- a/eth2/types/src/slot_epoch_macros.rs +++ b/eth2/types/src/slot_epoch_macros.rs @@ -192,30 +192,74 @@ macro_rules! impl_display { macro_rules! impl_ssz { ($type: ident) => { - impl Encodable for $type { - fn ssz_append(&self, s: &mut SszStream) { - s.append(&self.0); + impl Encode for $type { + fn is_ssz_fixed_len() -> bool { + ::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + ::ssz_fixed_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + self.0.ssz_append(buf) } } - impl Decodable for $type { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (value, i) = <_>::ssz_decode(bytes, i)?; + impl Decode for $type { + fn is_ssz_fixed_len() -> bool { + ::is_ssz_fixed_len() + } - Ok(($type(value), i)) + fn ssz_fixed_len() -> usize { + ::ssz_fixed_len() + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + Ok($type(u64::from_ssz_bytes(bytes)?)) } } - impl TreeHash for $type { - fn hash_tree_root(&self) -> Vec { - let mut result: Vec = vec![]; - result.append(&mut self.0.hash_tree_root()); - hash(&result) + impl tree_hash::TreeHash for $type { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::Basic + } + + fn tree_hash_packed_encoding(&self) -> Vec { + ssz_encode(self) + } + + fn tree_hash_packing_factor() -> usize { + 32 / 8 + } + + fn tree_hash_root(&self) -> Vec { + int_to_bytes::int_to_bytes32(self.0) } } - impl TestRandom for $type { - fn random_for_test(rng: &mut T) -> Self { + impl cached_tree_hash::CachedTreeHash for $type { + fn new_tree_hash_cache( + &self, + depth: usize, + ) -> Result { + self.0.new_tree_hash_cache(depth) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema { + self.0.tree_hash_cache_schema(depth) + } + + fn update_tree_hash_cache( + &self, + cache: &mut cached_tree_hash::TreeHashCache, + ) -> Result<(), cached_tree_hash::Error> { + self.0.update_tree_hash_cache(cache) + } + } + + impl TestRandom for $type { + fn random_for_test(rng: &mut impl RngCore) -> Self { $type::from(u64::random_for_test(rng)) } } @@ -535,6 +579,7 @@ macro_rules! all_tests { math_between_tests!($type, $type); math_tests!($type); ssz_tests!($type); + cached_tree_hash_tests!($type); mod u64_tests { use super::*; diff --git a/eth2/types/src/slot_height.rs b/eth2/types/src/slot_height.rs index 4a783d4a0..47db392a9 100644 --- a/eth2/types/src/slot_height.rs +++ b/eth2/types/src/slot_height.rs @@ -1,8 +1,9 @@ use crate::slot_epoch::{Epoch, Slot}; use crate::test_utils::TestRandom; + use rand::RngCore; use serde_derive::Serialize; -use ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError, Encode}; use std::cmp::{Ord, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; diff --git a/eth2/types/src/test_utils/generate_deterministic_keypairs.rs b/eth2/types/src/test_utils/generate_deterministic_keypairs.rs index 37880a988..ec1c15f29 100644 --- a/eth2/types/src/test_utils/generate_deterministic_keypairs.rs +++ b/eth2/types/src/test_utils/generate_deterministic_keypairs.rs @@ -18,13 +18,17 @@ pub fn generate_deterministic_keypairs(validator_count: usize) -> Vec { let keypairs: Vec = (0..validator_count) .collect::>() .par_iter() - .map(|&i| { - let secret = int_to_bytes48(i as u64 + 1000); - let sk = SecretKey::from_bytes(&secret).unwrap(); - let pk = PublicKey::from_secret_key(&sk); - Keypair { sk, pk } - }) + .map(|&i| generate_deterministic_keypair(i)) .collect(); - keypairs } + +/// Generates a single deterministic keypair, where the secret key is `validator_index`. +/// +/// This is used for testing only, and not to be used in production! +pub fn generate_deterministic_keypair(validator_index: usize) -> Keypair { + let secret = int_to_bytes48(validator_index as u64 + 1000); + let sk = SecretKey::from_bytes(&secret).unwrap(); + let pk = PublicKey::from_secret_key(&sk); + Keypair { sk, pk } +} diff --git a/eth2/types/src/test_utils/macros.rs b/eth2/types/src/test_utils/macros.rs index d580fd818..b060882f2 100644 --- a/eth2/types/src/test_utils/macros.rs +++ b/eth2/types/src/test_utils/macros.rs @@ -5,26 +5,26 @@ macro_rules! ssz_tests { #[test] pub fn test_ssz_round_trip() { use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use ssz::{ssz_encode, Decodable}; + use ssz::{ssz_encode, Decode}; let mut rng = XorShiftRng::from_seed([42; 16]); let original = $type::random_for_test(&mut rng); let bytes = ssz_encode(&original); - let (decoded, _): ($type, usize) = <_>::ssz_decode(&bytes, 0).unwrap(); + let decoded = $type::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } #[test] - pub fn test_hash_tree_root() { + pub fn test_tree_hash_root() { use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use ssz::TreeHash; + use tree_hash::TreeHash; let mut rng = XorShiftRng::from_seed([42; 16]); let original = $type::random_for_test(&mut rng); - let result = original.hash_tree_root(); + let result = original.tree_hash_root(); assert_eq!(result.len(), 32); // TODO: Add further tests @@ -32,3 +32,51 @@ macro_rules! ssz_tests { } }; } + +#[cfg(test)] +#[macro_export] +macro_rules! cached_tree_hash_tests { + ($type: ident) => { + #[test] + pub fn test_cached_tree_hash() { + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use tree_hash::TreeHash; + + let mut rng = XorShiftRng::from_seed([42; 16]); + + // Test the original hash + let original = $type::random_for_test(&mut rng); + let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + original.tree_hash_root(), + "Original hash failed." + ); + + // Test the updated hash + let modified = $type::random_for_test(&mut rng); + cache.update(&modified).unwrap(); + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + modified.tree_hash_root(), + "Modification hash failed" + ); + + // Produce a new cache for the modified object and compare it to the updated cache. + let mut modified_cache = cached_tree_hash::TreeHashCache::new(&modified).unwrap(); + + // Reset the caches. + cache.reset_modifications(); + modified_cache.reset_modifications(); + + // Ensure the modified cache is the same as a newly created cache. This is a sanity + // check to make sure there are no artifacts of the original cache remaining after an + // update. + assert_eq!( + modified_cache, cache, + "The modified cache does not match a new cache." + ) + } + }; +} diff --git a/eth2/types/src/test_utils/mod.rs b/eth2/types/src/test_utils/mod.rs index 018b70d15..20d53e72e 100644 --- a/eth2/types/src/test_utils/mod.rs +++ b/eth2/types/src/test_utils/mod.rs @@ -15,9 +15,13 @@ mod testing_proposer_slashing_builder; mod testing_transfer_builder; mod testing_voluntary_exit_builder; +pub use generate_deterministic_keypairs::generate_deterministic_keypair; pub use generate_deterministic_keypairs::generate_deterministic_keypairs; pub use keypairs_file::KeypairsFile; -pub use rand::{prng::XorShiftRng, SeedableRng}; +pub use rand::{ + RngCore, + {prng::XorShiftRng, SeedableRng}, +}; pub use serde_utils::{fork_from_hex_str, u8_from_hex_str}; pub use test_random::TestRandom; pub use testing_attestation_builder::TestingAttestationBuilder; diff --git a/eth2/types/src/test_utils/test_random.rs b/eth2/types/src/test_utils/test_random.rs index cb7abe3a4..ceb785424 100644 --- a/eth2/types/src/test_utils/test_random.rs +++ b/eth2/types/src/test_utils/test_random.rs @@ -1,3 +1,5 @@ +use crate::*; +use fixed_len_vec::typenum::Unsigned; use rand::RngCore; mod address; @@ -8,54 +10,68 @@ mod public_key; mod secret_key; mod signature; -pub trait TestRandom -where - T: RngCore, -{ - fn random_for_test(rng: &mut T) -> Self; +pub trait TestRandom { + fn random_for_test(rng: &mut impl RngCore) -> Self; } -impl TestRandom for bool { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for bool { + fn random_for_test(rng: &mut impl RngCore) -> Self { (rng.next_u32() % 2) == 1 } } -impl TestRandom for u64 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for u64 { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u64() } } -impl TestRandom for u32 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for u32 { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u32() } } -impl TestRandom for usize { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for usize { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u32() as usize } } -impl TestRandom for Vec +impl TestRandom for Vec where - U: TestRandom, + U: TestRandom, { - fn random_for_test(rng: &mut T) -> Self { - vec![ - ::random_for_test(rng), - ::random_for_test(rng), - ::random_for_test(rng), - ] + fn random_for_test(rng: &mut impl RngCore) -> Self { + let mut output = vec![]; + + for _ in 0..(usize::random_for_test(rng) % 4) { + output.push(::random_for_test(rng)); + } + + output + } +} + +impl TestRandom for FixedLenVec +where + T: TestRandom + Default, +{ + fn random_for_test(rng: &mut impl RngCore) -> Self { + let mut output = vec![]; + + for _ in 0..(usize::random_for_test(rng) % std::cmp::min(4, N::to_usize())) { + output.push(::random_for_test(rng)); + } + + output.into() } } macro_rules! impl_test_random_for_u8_array { ($len: expr) => { - impl TestRandom for [u8; $len] { - fn random_for_test(rng: &mut T) -> Self { + impl TestRandom for [u8; $len] { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut bytes = [0; $len]; rng.fill_bytes(&mut bytes); bytes diff --git a/eth2/types/src/test_utils/test_random/address.rs b/eth2/types/src/test_utils/test_random/address.rs index 13de2dec9..3aaad307e 100644 --- a/eth2/types/src/test_utils/test_random/address.rs +++ b/eth2/types/src/test_utils/test_random/address.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Address; -use rand::RngCore; -impl TestRandom for Address { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Address { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 20]; rng.fill_bytes(&mut key_bytes); Address::from_slice(&key_bytes[..]) diff --git a/eth2/types/src/test_utils/test_random/aggregate_signature.rs b/eth2/types/src/test_utils/test_random/aggregate_signature.rs index 6a15f7366..a346d2d88 100644 --- a/eth2/types/src/test_utils/test_random/aggregate_signature.rs +++ b/eth2/types/src/test_utils/test_random/aggregate_signature.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{AggregateSignature, Signature}; -use rand::RngCore; -impl TestRandom for AggregateSignature { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for AggregateSignature { + fn random_for_test(rng: &mut impl RngCore) -> Self { let signature = Signature::random_for_test(rng); let mut aggregate_signature = AggregateSignature::new(); aggregate_signature.add(&signature); diff --git a/eth2/types/src/test_utils/test_random/bitfield.rs b/eth2/types/src/test_utils/test_random/bitfield.rs index 9748458f1..9a4d21840 100644 --- a/eth2/types/src/test_utils/test_random/bitfield.rs +++ b/eth2/types/src/test_utils/test_random/bitfield.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Bitfield; -use rand::RngCore; -impl TestRandom for Bitfield { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Bitfield { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut raw_bytes = vec![0; 32]; rng.fill_bytes(&mut raw_bytes); Bitfield::from_bytes(&raw_bytes) diff --git a/eth2/types/src/test_utils/test_random/hash256.rs b/eth2/types/src/test_utils/test_random/hash256.rs index a227679da..8733f7de2 100644 --- a/eth2/types/src/test_utils/test_random/hash256.rs +++ b/eth2/types/src/test_utils/test_random/hash256.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Hash256; -use rand::RngCore; -impl TestRandom for Hash256 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Hash256 { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 32]; rng.fill_bytes(&mut key_bytes); Hash256::from_slice(&key_bytes[..]) diff --git a/eth2/types/src/test_utils/test_random/public_key.rs b/eth2/types/src/test_utils/test_random/public_key.rs index bfccd3e53..d643eaf0b 100644 --- a/eth2/types/src/test_utils/test_random/public_key.rs +++ b/eth2/types/src/test_utils/test_random/public_key.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{PublicKey, SecretKey}; -use rand::RngCore; -impl TestRandom for PublicKey { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for PublicKey { + fn random_for_test(rng: &mut impl RngCore) -> Self { let secret_key = SecretKey::random_for_test(rng); PublicKey::from_secret_key(&secret_key) } diff --git a/eth2/types/src/test_utils/test_random/secret_key.rs b/eth2/types/src/test_utils/test_random/secret_key.rs index 17481c3de..a833a4488 100644 --- a/eth2/types/src/test_utils/test_random/secret_key.rs +++ b/eth2/types/src/test_utils/test_random/secret_key.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::SecretKey; -use rand::RngCore; -impl TestRandom for SecretKey { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for SecretKey { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 48]; rng.fill_bytes(&mut key_bytes); /* diff --git a/eth2/types/src/test_utils/test_random/signature.rs b/eth2/types/src/test_utils/test_random/signature.rs index d9995835a..ef5d9a17f 100644 --- a/eth2/types/src/test_utils/test_random/signature.rs +++ b/eth2/types/src/test_utils/test_random/signature.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{SecretKey, Signature}; -use rand::RngCore; -impl TestRandom for Signature { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Signature { + fn random_for_test(rng: &mut impl RngCore) -> Self { let secret_key = SecretKey::random_for_test(rng); let mut message = vec![0; 32]; rng.fill_bytes(&mut message); diff --git a/eth2/types/src/test_utils/testing_attestation_builder.rs b/eth2/types/src/test_utils/testing_attestation_builder.rs index 60624b48d..0df1c01b8 100644 --- a/eth2/types/src/test_utils/testing_attestation_builder.rs +++ b/eth2/types/src/test_utils/testing_attestation_builder.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestingAttestationDataBuilder; use crate::*; -use ssz::TreeHash; +use tree_hash::TreeHash; /// Builds an attestation to be used for testing purposes. /// @@ -12,8 +12,8 @@ pub struct TestingAttestationBuilder { impl TestingAttestationBuilder { /// Create a new attestation builder. - pub fn new( - state: &BeaconState, + pub fn new( + state: &BeaconState, committee: &[usize], slot: Slot, shard: u64, @@ -74,7 +74,7 @@ impl TestingAttestationBuilder { data: self.attestation.data.clone(), custody_bit: false, } - .hash_tree_root(); + .tree_hash_root(); let domain = spec.get_domain( self.attestation.data.slot.epoch(spec.slots_per_epoch), diff --git a/eth2/types/src/test_utils/testing_attestation_data_builder.rs b/eth2/types/src/test_utils/testing_attestation_data_builder.rs index a270e3859..fbe79df1e 100644 --- a/eth2/types/src/test_utils/testing_attestation_data_builder.rs +++ b/eth2/types/src/test_utils/testing_attestation_data_builder.rs @@ -10,7 +10,12 @@ pub struct TestingAttestationDataBuilder { impl TestingAttestationDataBuilder { /// Configures a new `AttestationData` which attests to all of the same parameters as the /// state. - pub fn new(state: &BeaconState, shard: u64, slot: Slot, spec: &ChainSpec) -> Self { + pub fn new( + state: &BeaconState, + shard: u64, + slot: Slot, + spec: &ChainSpec, + ) -> Self { let current_epoch = state.current_epoch(spec); let previous_epoch = state.previous_epoch(spec); @@ -25,22 +30,22 @@ impl TestingAttestationDataBuilder { let target_root = if is_previous_epoch { *state - .get_block_root(previous_epoch.start_slot(spec.slots_per_epoch), spec) + .get_block_root(previous_epoch.start_slot(spec.slots_per_epoch)) .unwrap() } else { *state - .get_block_root(current_epoch.start_slot(spec.slots_per_epoch), spec) + .get_block_root(current_epoch.start_slot(spec.slots_per_epoch)) .unwrap() }; let source_root = *state - .get_block_root(source_epoch.start_slot(spec.slots_per_epoch), spec) + .get_block_root(source_epoch.start_slot(spec.slots_per_epoch)) .unwrap(); let data = AttestationData { // LMD GHOST vote slot, - beacon_block_root: *state.get_block_root(slot, spec).unwrap(), + beacon_block_root: *state.get_block_root(slot).unwrap(), // FFG Vote source_epoch, diff --git a/eth2/types/src/test_utils/testing_attester_slashing_builder.rs b/eth2/types/src/test_utils/testing_attester_slashing_builder.rs index fcaa3285b..dc01f7fb0 100644 --- a/eth2/types/src/test_utils/testing_attester_slashing_builder.rs +++ b/eth2/types/src/test_utils/testing_attester_slashing_builder.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::TreeHash; +use tree_hash::TreeHash; /// Builds an `AttesterSlashing`. /// @@ -66,7 +66,7 @@ impl TestingAttesterSlashingBuilder { data: attestation.data.clone(), custody_bit: false, }; - let message = attestation_data_and_custody_bit.hash_tree_root(); + let message = attestation_data_and_custody_bit.tree_hash_root(); for (i, validator_index) in validator_indices.iter().enumerate() { attestation.custody_bitfield.set(i, false); diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index c28311002..9c75bde0e 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -6,7 +6,7 @@ use crate::{ *, }; use rayon::prelude::*; -use ssz::{SignedRoot, TreeHash}; +use tree_hash::{SignedRoot, TreeHash}; /// Builds a beacon block to be used for testing purposes. /// @@ -43,7 +43,7 @@ impl TestingBeaconBlockBuilder { /// Modifying the block's slot after signing may invalidate the signature. pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) { let epoch = self.block.slot.epoch(spec.slots_per_epoch); - let message = epoch.hash_tree_root(); + let message = epoch.tree_hash_root(); let domain = spec.get_domain(epoch, Domain::Randao, fork); self.block.body.randao_reveal = Signature::new(&message, domain, sk); } @@ -87,9 +87,9 @@ impl TestingBeaconBlockBuilder { /// /// Note: the signed messages of the split committees will be identical -- it would be possible /// to aggregate these split attestations. - pub fn insert_attestations( + pub fn insert_attestations( &mut self, - state: &BeaconState, + state: &BeaconState, secret_keys: &[&SecretKey], num_attestations: usize, spec: &ChainSpec, @@ -176,11 +176,11 @@ impl TestingBeaconBlockBuilder { } /// Insert a `Valid` deposit into the state. - pub fn insert_deposit( + pub fn insert_deposit( &mut self, amount: u64, index: u64, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) { let keypair = Keypair::random(); @@ -198,9 +198,9 @@ impl TestingBeaconBlockBuilder { } /// Insert a `Valid` exit into the state. - pub fn insert_exit( + pub fn insert_exit( &mut self, - state: &BeaconState, + state: &BeaconState, validator_index: u64, secret_key: &SecretKey, spec: &ChainSpec, @@ -219,9 +219,9 @@ impl TestingBeaconBlockBuilder { /// /// Note: this will set the validator to be withdrawable by directly modifying the state /// validator registry. This _may_ cause problems historic hashes, etc. - pub fn insert_transfer( + pub fn insert_transfer( &mut self, - state: &BeaconState, + state: &BeaconState, from: u64, to: u64, amount: u64, diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 9bdd9e149..727b70d93 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -25,12 +25,12 @@ pub fn keypairs_path() -> PathBuf { /// /// This struct should **never be used for production purposes.** #[derive(Clone)] -pub struct TestingBeaconStateBuilder { - state: BeaconState, +pub struct TestingBeaconStateBuilder { + state: BeaconState, keypairs: Vec, } -impl TestingBeaconStateBuilder { +impl TestingBeaconStateBuilder { /// Attempts to load validators from a file in `$HOME/.lighthouse/keypairs.raw_keypairs`. If /// the file is unavailable, it generates the keys at runtime. /// @@ -154,7 +154,7 @@ impl TestingBeaconStateBuilder { } /// Consume the builder and return the `BeaconState` and the keypairs for each validator. - pub fn build(self) -> (BeaconState, Vec) { + pub fn build(self) -> (BeaconState, Vec) { (self.state, self.keypairs) } diff --git a/eth2/types/src/test_utils/testing_deposit_builder.rs b/eth2/types/src/test_utils/testing_deposit_builder.rs index 326858c31..080ed5cfb 100644 --- a/eth2/types/src/test_utils/testing_deposit_builder.rs +++ b/eth2/types/src/test_utils/testing_deposit_builder.rs @@ -12,7 +12,7 @@ impl TestingDepositBuilder { /// Instantiates a new builder. pub fn new(pubkey: PublicKey, amount: u64) -> Self { let deposit = Deposit { - proof: vec![], + proof: vec![].into(), index: 0, deposit_data: DepositData { amount, diff --git a/eth2/types/src/test_utils/testing_pending_attestation_builder.rs b/eth2/types/src/test_utils/testing_pending_attestation_builder.rs index 655b3d1e8..023b039b0 100644 --- a/eth2/types/src/test_utils/testing_pending_attestation_builder.rs +++ b/eth2/types/src/test_utils/testing_pending_attestation_builder.rs @@ -16,7 +16,12 @@ impl TestingPendingAttestationBuilder { /// /// * The aggregation and custody bitfields will all be empty, they need to be set with /// `Self::add_committee_participation`. - pub fn new(state: &BeaconState, shard: u64, slot: Slot, spec: &ChainSpec) -> Self { + pub fn new( + state: &BeaconState, + shard: u64, + slot: Slot, + spec: &ChainSpec, + ) -> Self { let data_builder = TestingAttestationDataBuilder::new(state, shard, slot, spec); let pending_attestation = PendingAttestation { diff --git a/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs b/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs index 2cfebd915..03c257b2d 100644 --- a/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs +++ b/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::SignedRoot; +use tree_hash::SignedRoot; /// Builds a `ProposerSlashing`. /// diff --git a/eth2/types/src/test_utils/testing_transfer_builder.rs b/eth2/types/src/test_utils/testing_transfer_builder.rs index 354e29aa5..2680f7b66 100644 --- a/eth2/types/src/test_utils/testing_transfer_builder.rs +++ b/eth2/types/src/test_utils/testing_transfer_builder.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::SignedRoot; +use tree_hash::SignedRoot; /// Builds a transfer to be used for testing purposes. /// diff --git a/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs b/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs index fe5c8325a..8583bc451 100644 --- a/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs +++ b/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::SignedRoot; +use tree_hash::SignedRoot; /// Builds an exit to be used for testing purposes. /// diff --git a/eth2/types/src/transfer.rs b/eth2/types/src/transfer.rs index f291190b2..176a9d75d 100644 --- a/eth2/types/src/transfer.rs +++ b/eth2/types/src/transfer.rs @@ -2,15 +2,16 @@ use super::Slot; use crate::test_utils::TestRandom; use bls::{PublicKey, Signature}; use derivative::Derivative; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// The data submitted to the deposit contract. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, Clone, @@ -19,6 +20,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, Derivative, @@ -41,4 +43,5 @@ mod tests { use super::*; ssz_tests!(Transfer); + cached_tree_hash_tests!(Transfer); } diff --git a/eth2/types/src/validator.rs b/eth2/types/src/validator.rs index f57261175..ff4cabf35 100644 --- a/eth2/types/src/validator.rs +++ b/eth2/types/src/validator.rs @@ -1,13 +1,25 @@ use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKey}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash_derive::{CachedTreeHash, TreeHash}; /// Information about a `BeaconChain` validator. /// -/// Spec v0.5.0 -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)] +/// Spec v0.5.1 +#[derive( + Debug, + Clone, + PartialEq, + Serialize, + Deserialize, + Encode, + Decode, + TestRandom, + TreeHash, + CachedTreeHash, +)] pub struct Validator { pub pubkey: PublicKey, pub withdrawal_credentials: Hash256, @@ -110,4 +122,5 @@ mod tests { } ssz_tests!(Validator); + cached_tree_hash_tests!(Validator); } diff --git a/eth2/types/src/voluntary_exit.rs b/eth2/types/src/voluntary_exit.rs index 0cdc63149..a138fb480 100644 --- a/eth2/types/src/voluntary_exit.rs +++ b/eth2/types/src/voluntary_exit.rs @@ -1,14 +1,15 @@ use crate::{test_utils::TestRandom, Epoch}; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; -use ssz::TreeHash; -use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; +use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; +use tree_hash::TreeHash; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; /// An exit voluntarily submitted a validator who wishes to withdraw. /// -/// Spec v0.5.0 +/// Spec v0.5.1 #[derive( Debug, PartialEq, @@ -18,6 +19,7 @@ use test_random_derive::TestRandom; Encode, Decode, TreeHash, + CachedTreeHash, TestRandom, SignedRoot, )] @@ -33,4 +35,5 @@ mod tests { use super::*; ssz_tests!(VoluntaryExit); + cached_tree_hash_tests!(VoluntaryExit); } diff --git a/eth2/utils/bls/Cargo.toml b/eth2/utils/bls/Cargo.toml index 4230a06ea..dcace15c8 100644 --- a/eth2/utils/bls/Cargo.toml +++ b/eth2/utils/bls/Cargo.toml @@ -6,9 +6,14 @@ edition = "2018" [dependencies] bls-aggregates = { git = "https://github.com/sigp/signature-schemes", tag = "0.6.1" } +cached_tree_hash = { path = "../cached_tree_hash" } hashing = { path = "../hashing" } hex = "0.3" serde = "1.0" serde_derive = "1.0" serde_hex = { path = "../serde_hex" } ssz = { path = "../ssz" } +tree_hash = { path = "../tree_hash" } + +[features] +fake_crypto = [] diff --git a/eth2/utils/bls/build.rs b/eth2/utils/bls/build.rs new file mode 100644 index 000000000..7f08a1ed5 --- /dev/null +++ b/eth2/utils/bls/build.rs @@ -0,0 +1,19 @@ +// This build script is symlinked from each project that requires BLS's "fake crypto", +// so that the `fake_crypto` feature of every sub-crate can be turned on by running +// with FAKE_CRYPTO=1 from the top-level workspace. +// At some point in the future it might be possible to do: +// $ cargo test --all --release --features fake_crypto +// but at the present time this doesn't work. +// Related: https://github.com/rust-lang/cargo/issues/5364 +fn main() { + if let Ok(fake_crypto) = std::env::var("FAKE_CRYPTO") { + if fake_crypto == "1" { + println!("cargo:rustc-cfg=feature=\"fake_crypto\""); + println!("cargo:rerun-if-env-changed=FAKE_CRYPTO"); + println!( + "cargo:warning=[{}]: Compiled with fake BLS cryptography. DO NOT USE, TESTING ONLY", + std::env::var("CARGO_PKG_NAME").unwrap() + ); + } + } +} diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 8c7ae5222..2e4615324 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -1,11 +1,13 @@ -use super::{AggregatePublicKey, Signature, BLS_AGG_SIG_BYTE_SIZE}; +use super::*; use bls_aggregates::{ AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature, }; +use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, HexVisitor}; -use ssz::{decode, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{Decode, DecodeError}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A BLS aggregate signature. /// @@ -97,8 +99,12 @@ impl AggregateSignature { pub fn from_bytes(bytes: &[u8]) -> Result { for byte in bytes { if *byte != 0 { - let sig = - RawAggregateSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let sig = RawAggregateSignature::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid( + format!("Invalid AggregateSignature bytes: {:?}", bytes).to_string(), + ) + })?; + return Ok(Self { aggregate_signature: sig, is_empty: false, @@ -125,22 +131,11 @@ impl AggregateSignature { } } -impl Encodable for AggregateSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.as_bytes()); - } -} - -impl Decodable for AggregateSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_AGG_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let agg_sig = AggregateSignature::from_bytes(&bytes[i..(i + BLS_AGG_SIG_BYTE_SIZE)]) - .map_err(|_| DecodeError::Invalid)?; - Ok((agg_sig, i + BLS_AGG_SIG_BYTE_SIZE)) - } -} +impl_ssz!( + AggregateSignature, + BLS_AGG_SIG_BYTE_SIZE, + "AggregateSignature" +); impl Serialize for AggregateSignature { /// Serde serialization is compliant the Ethereum YAML test format. @@ -159,23 +154,21 @@ impl<'de> Deserialize<'de> for AggregateSignature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let agg_sig = decode(&bytes[..]) + let agg_sig = AggregateSignature::from_ssz_bytes(&bytes) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; + Ok(agg_sig) } } -impl TreeHash for AggregateSignature { - fn hash_tree_root(&self) -> Vec { - hash(&self.as_bytes()) - } -} +tree_hash_ssz_encoding_as_vector!(AggregateSignature); +cached_tree_hash_ssz_encoding_as_vector!(AggregateSignature, 96); #[cfg(test)] mod tests { use super::super::{Keypair, Signature}; use super::*; - use ssz::{decode, ssz_encode}; + use ssz::Encode; #[test] pub fn test_ssz_round_trip() { @@ -184,8 +177,8 @@ mod tests { let mut original = AggregateSignature::new(); original.add(&Signature::new(&[42, 42], 0, &keypair.sk)); - let bytes = ssz_encode(&original); - let decoded = decode::(&bytes).unwrap(); + let bytes = original.as_ssz_bytes(); + let decoded = AggregateSignature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/fake_aggregate_signature.rs b/eth2/utils/bls/src/fake_aggregate_signature.rs index 3f0ec0d6d..12532d080 100644 --- a/eth2/utils/bls/src/fake_aggregate_signature.rs +++ b/eth2/utils/bls/src/fake_aggregate_signature.rs @@ -1,8 +1,10 @@ use super::{fake_signature::FakeSignature, AggregatePublicKey, BLS_AGG_SIG_BYTE_SIZE}; +use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; -use ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A BLS aggregate signature. /// @@ -55,28 +57,32 @@ impl FakeAggregateSignature { ) -> bool { true } -} -impl Encodable for FakeAggregateSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.bytes); - } -} - -impl Decodable for FakeAggregateSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_AGG_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); + /// Convert bytes to fake BLS aggregate signature + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != BLS_AGG_SIG_BYTE_SIZE { + Err(DecodeError::InvalidByteLength { + len: bytes.len(), + expected: BLS_AGG_SIG_BYTE_SIZE, + }) + } else { + Ok(Self { + bytes: bytes.to_vec(), + }) } - Ok(( - FakeAggregateSignature { - bytes: bytes[i..(i + BLS_AGG_SIG_BYTE_SIZE)].to_vec(), - }, - i + BLS_AGG_SIG_BYTE_SIZE, - )) + } + + pub fn as_bytes(&self) -> Vec { + self.bytes.clone() } } +impl_ssz!( + FakeAggregateSignature, + BLS_AGG_SIG_BYTE_SIZE, + "FakeAggregateSignature" +); + impl Serialize for FakeAggregateSignature { fn serialize(&self, serializer: S) -> Result where @@ -92,17 +98,14 @@ impl<'de> Deserialize<'de> for FakeAggregateSignature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - let (obj, _) = <_>::ssz_decode(&bytes[..], 0) + let obj = <_>::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(obj) } } -impl TreeHash for FakeAggregateSignature { - fn hash_tree_root(&self) -> Vec { - hash(&self.bytes) - } -} +tree_hash_ssz_encoding_as_vector!(FakeAggregateSignature); +cached_tree_hash_ssz_encoding_as_vector!(FakeAggregateSignature, 96); #[cfg(test)] mod tests { @@ -118,7 +121,7 @@ mod tests { original.add(&Signature::new(&[42, 42], 0, &keypair.sk)); let bytes = ssz_encode(&original); - let (decoded, _) = FakeAggregateSignature::ssz_decode(&bytes, 0).unwrap(); + let decoded = FakeAggregateSignature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/fake_signature.rs b/eth2/utils/bls/src/fake_signature.rs index 3c9f3a9f4..0bf3d0a25 100644 --- a/eth2/utils/bls/src/fake_signature.rs +++ b/eth2/utils/bls/src/fake_signature.rs @@ -1,9 +1,11 @@ use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE}; +use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. /// @@ -47,37 +49,34 @@ impl FakeSignature { true } + /// Convert bytes to fake BLS Signature + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != BLS_SIG_BYTE_SIZE { + Err(DecodeError::InvalidByteLength { + len: bytes.len(), + expected: BLS_SIG_BYTE_SIZE, + }) + } else { + Ok(Self { + bytes: bytes.to_vec(), + }) + } + } + + pub fn as_bytes(&self) -> Vec { + self.bytes.clone() + } + /// Returns a new empty signature. pub fn empty_signature() -> Self { FakeSignature::zero() } } -impl Encodable for FakeSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.bytes); - } -} +impl_ssz!(FakeSignature, BLS_SIG_BYTE_SIZE, "FakeSignature"); -impl Decodable for FakeSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - Ok(( - FakeSignature { - bytes: bytes[i..(i + BLS_SIG_BYTE_SIZE)].to_vec(), - }, - i + BLS_SIG_BYTE_SIZE, - )) - } -} - -impl TreeHash for FakeSignature { - fn hash_tree_root(&self) -> Vec { - hash(&self.bytes) - } -} +tree_hash_ssz_encoding_as_vector!(FakeSignature); +cached_tree_hash_ssz_encoding_as_vector!(FakeSignature, 96); impl Serialize for FakeSignature { fn serialize(&self, serializer: S) -> Result @@ -94,7 +93,7 @@ impl<'de> Deserialize<'de> for FakeSignature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) + let pubkey = <_>::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(pubkey) } @@ -113,7 +112,7 @@ mod tests { let original = FakeSignature::new(&[42, 42], 0, &keypair.sk); let bytes = ssz_encode(&original); - let (decoded, _) = FakeSignature::ssz_decode(&bytes, 0).unwrap(); + let decoded = FakeSignature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index caf56ae74..afe655939 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -1,16 +1,30 @@ extern crate bls_aggregates; extern crate ssz; +#[macro_use] +mod macros; mod aggregate_public_key; mod keypair; mod public_key; mod secret_key; +#[cfg(not(feature = "fake_crypto"))] mod aggregate_signature; +#[cfg(not(feature = "fake_crypto"))] mod signature; +#[cfg(not(feature = "fake_crypto"))] pub use crate::aggregate_signature::AggregateSignature; +#[cfg(not(feature = "fake_crypto"))] pub use crate::signature::Signature; +#[cfg(feature = "fake_crypto")] +mod fake_aggregate_signature; +#[cfg(feature = "fake_crypto")] +mod fake_signature; +#[cfg(feature = "fake_crypto")] +pub use crate::fake_aggregate_signature::FakeAggregateSignature as AggregateSignature; +#[cfg(feature = "fake_crypto")] +pub use crate::fake_signature::FakeSignature as Signature; pub use crate::aggregate_public_key::AggregatePublicKey; pub use crate::keypair::Keypair; diff --git a/eth2/utils/bls/src/macros.rs b/eth2/utils/bls/src/macros.rs new file mode 100644 index 000000000..af2cde190 --- /dev/null +++ b/eth2/utils/bls/src/macros.rs @@ -0,0 +1,38 @@ +macro_rules! impl_ssz { + ($type: ident, $byte_size: expr, $item_str: expr) => { + impl ssz::Encode for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $byte_size + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.append(&mut self.as_bytes()) + } + } + + impl ssz::Decode for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $byte_size + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(ssz::DecodeError::InvalidByteLength { len, expected }) + } else { + $type::from_bytes(bytes) + } + } + } + }; +} diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 177a735c4..f72bb7646 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -1,12 +1,14 @@ use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE}; use bls_aggregates::PublicKey as RawPublicKey; +use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, HexVisitor}; -use ssz::{decode, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError}; use std::default; use std::fmt; use std::hash::{Hash, Hasher}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. /// @@ -25,9 +27,19 @@ impl PublicKey { &self.0 } + /// Returns the underlying point as compressed bytes. + /// + /// Identical to `self.as_uncompressed_bytes()`. + fn as_bytes(&self) -> Vec { + self.as_raw().as_bytes() + } + /// Converts compressed bytes to PublicKey pub fn from_bytes(bytes: &[u8]) -> Result { - let pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid(format!("Invalid PublicKey bytes: {:?}", bytes).to_string()) + })?; + Ok(PublicKey(pubkey)) } @@ -38,8 +50,9 @@ impl PublicKey { /// Converts (x, y) bytes to PublicKey pub fn from_uncompressed_bytes(bytes: &[u8]) -> Result { - let pubkey = - RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let pubkey = RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid("Invalid PublicKey uncompressed bytes.".to_string()) + })?; Ok(PublicKey(pubkey)) } @@ -66,22 +79,7 @@ impl default::Default for PublicKey { } } -impl Encodable for PublicKey { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.0.as_bytes()); - } -} - -impl Decodable for PublicKey { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_PUBLIC_KEY_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let raw_sig = RawPublicKey::from_bytes(&bytes[i..(i + BLS_PUBLIC_KEY_BYTE_SIZE)]) - .map_err(|_| DecodeError::TooShort)?; - Ok((PublicKey(raw_sig), i + BLS_PUBLIC_KEY_BYTE_SIZE)) - } -} +impl_ssz!(PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE, "PublicKey"); impl Serialize for PublicKey { fn serialize(&self, serializer: S) -> Result @@ -98,17 +96,14 @@ impl<'de> Deserialize<'de> for PublicKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let pubkey = decode(&bytes[..]) + let pubkey = Self::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid pubkey ({:?})", e)))?; Ok(pubkey) } } -impl TreeHash for PublicKey { - fn hash_tree_root(&self) -> Vec { - hash(&self.0.as_bytes()) - } -} +tree_hash_ssz_encoding_as_vector!(PublicKey); +cached_tree_hash_ssz_encoding_as_vector!(PublicKey, 48); impl PartialEq for PublicKey { fn eq(&self, other: &PublicKey) -> bool { @@ -132,6 +127,7 @@ impl Hash for PublicKey { mod tests { use super::*; use ssz::ssz_encode; + use tree_hash::TreeHash; #[test] pub fn test_ssz_round_trip() { @@ -139,8 +135,31 @@ mod tests { let original = PublicKey::from_secret_key(&sk); let bytes = ssz_encode(&original); - let (decoded, _) = PublicKey::ssz_decode(&bytes, 0).unwrap(); + let decoded = PublicKey::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } + + #[test] + pub fn test_cached_tree_hash() { + let sk = SecretKey::random(); + let original = PublicKey::from_secret_key(&sk); + + let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + original.tree_hash_root() + ); + + let sk = SecretKey::random(); + let modified = PublicKey::from_secret_key(&sk); + + cache.update(&modified).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + modified.tree_hash_root() + ); + } } diff --git a/eth2/utils/bls/src/secret_key.rs b/eth2/utils/bls/src/secret_key.rs index 40c469513..620780261 100644 --- a/eth2/utils/bls/src/secret_key.rs +++ b/eth2/utils/bls/src/secret_key.rs @@ -1,10 +1,11 @@ use super::BLS_SECRET_KEY_BYTE_SIZE; -use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey}; +use bls_aggregates::SecretKey as RawSecretKey; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{decode, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. /// @@ -18,11 +19,21 @@ impl SecretKey { SecretKey(RawSecretKey::random()) } + /// Returns the underlying point as compressed bytes. + fn as_bytes(&self) -> Vec { + self.as_raw().as_bytes() + } + /// Instantiate a SecretKey from existing bytes. /// /// Note: this is _not_ SSZ decoding. - pub fn from_bytes(bytes: &[u8]) -> Result { - Ok(SecretKey(RawSecretKey::from_bytes(bytes)?)) + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(SecretKey(RawSecretKey::from_bytes(bytes).map_err(|e| { + DecodeError::BytesInvalid(format!( + "Invalid SecretKey bytes: {:?} Error: {:?}", + bytes, e + )) + })?)) } /// Returns the underlying secret key. @@ -31,22 +42,7 @@ impl SecretKey { } } -impl Encodable for SecretKey { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.0.as_bytes()); - } -} - -impl Decodable for SecretKey { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SECRET_KEY_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let raw_sig = RawSecretKey::from_bytes(&bytes[i..(i + BLS_SECRET_KEY_BYTE_SIZE)]) - .map_err(|_| DecodeError::TooShort)?; - Ok((SecretKey(raw_sig), i + BLS_SECRET_KEY_BYTE_SIZE)) - } -} +impl_ssz!(SecretKey, BLS_SECRET_KEY_BYTE_SIZE, "SecretKey"); impl Serialize for SecretKey { fn serialize(&self, serializer: S) -> Result @@ -63,17 +59,13 @@ impl<'de> Deserialize<'de> for SecretKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let secret_key = decode::(&bytes[..]) + let secret_key = SecretKey::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(secret_key) } } -impl TreeHash for SecretKey { - fn hash_tree_root(&self) -> Vec { - self.0.as_bytes().clone() - } -} +tree_hash_ssz_encoding_as_vector!(SecretKey); #[cfg(test)] mod tests { @@ -87,7 +79,7 @@ mod tests { .unwrap(); let bytes = ssz_encode(&original); - let (decoded, _) = SecretKey::ssz_decode(&bytes, 0).unwrap(); + let decoded = SecretKey::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index d19af545f..5ad159828 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -1,10 +1,12 @@ use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE}; use bls_aggregates::Signature as RawSignature; +use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{decode, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ssz_encode, Decode, DecodeError}; +use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. /// @@ -81,8 +83,11 @@ impl Signature { pub fn from_bytes(bytes: &[u8]) -> Result { for byte in bytes { if *byte != 0 { - let raw_signature = - RawSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let raw_signature = RawSignature::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid( + format!("Invalid Signature bytes: {:?}", bytes).to_string(), + ) + })?; return Ok(Signature { signature: raw_signature, is_empty: false, @@ -98,27 +103,10 @@ impl Signature { } } -impl Encodable for Signature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.as_bytes()); - } -} +impl_ssz!(Signature, BLS_SIG_BYTE_SIZE, "Signature"); -impl Decodable for Signature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let signature = Signature::from_bytes(&bytes[i..(i + BLS_SIG_BYTE_SIZE)])?; - Ok((signature, i + BLS_SIG_BYTE_SIZE)) - } -} - -impl TreeHash for Signature { - fn hash_tree_root(&self) -> Vec { - hash(&self.as_bytes()) - } -} +tree_hash_ssz_encoding_as_vector!(Signature); +cached_tree_hash_ssz_encoding_as_vector!(Signature, 96); impl Serialize for Signature { /// Serde serialization is compliant the Ethereum YAML test format. @@ -137,7 +125,7 @@ impl<'de> Deserialize<'de> for Signature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let signature = decode(&bytes[..]) + let signature = Self::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(signature) } @@ -148,6 +136,7 @@ mod tests { use super::super::Keypair; use super::*; use ssz::ssz_encode; + use tree_hash::TreeHash; #[test] pub fn test_ssz_round_trip() { @@ -156,11 +145,33 @@ mod tests { let original = Signature::new(&[42, 42], 0, &keypair.sk); let bytes = ssz_encode(&original); - let decoded = decode::(&bytes).unwrap(); + let decoded = Signature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } + #[test] + pub fn test_cached_tree_hash() { + let keypair = Keypair::random(); + let original = Signature::new(&[42, 42], 0, &keypair.sk); + + let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + original.tree_hash_root() + ); + + let modified = Signature::new(&[99, 99], 0, &keypair.sk); + + cache.update(&modified).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + modified.tree_hash_root() + ); + } + #[test] pub fn test_empty_signature() { let sig = Signature::empty_signature(); diff --git a/eth2/utils/boolean-bitfield/Cargo.toml b/eth2/utils/boolean-bitfield/Cargo.toml index cf037c5d7..dfc97ce77 100644 --- a/eth2/utils/boolean-bitfield/Cargo.toml +++ b/eth2/utils/boolean-bitfield/Cargo.toml @@ -5,8 +5,14 @@ authors = ["Paul Hauner "] edition = "2018" [dependencies] +cached_tree_hash = { path = "../cached_tree_hash" } serde_hex = { path = "../serde_hex" } ssz = { path = "../ssz" } bit-vec = "0.5.0" +bit_reverse = "0.1" serde = "1.0" serde_derive = "1.0" +tree_hash = { path = "../tree_hash" } + +[dev-dependencies] +serde_yaml = "0.8" diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index d04516dba..08e56e7c3 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -1,12 +1,13 @@ extern crate bit_vec; extern crate ssz; +use bit_reverse::LookupReverse; use bit_vec::BitVec; - +use cached_tree_hash::cached_tree_hash_bytes_as_list; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode, PrefixedHexVisitor}; -use ssz::{Decodable, Encodable}; +use ssz::{Decode, Encode}; use std::cmp; use std::default; @@ -53,10 +54,15 @@ impl BooleanBitfield { /// Create a new bitfield using the supplied `bytes` as input pub fn from_bytes(bytes: &[u8]) -> Self { Self { - 0: BitVec::from_bytes(bytes), + 0: BitVec::from_bytes(&reverse_bit_order(bytes.to_vec())), } } + /// Returns a vector of bytes representing the bitfield + pub fn to_bytes(&self) -> Vec { + reverse_bit_order(self.0.to_bytes().to_vec()) + } + /// Read the value of a bit. /// /// If the index is in bounds, then result is Ok(value) where value is `true` if the bit is 1 and `false` if the bit is 0. @@ -85,11 +91,6 @@ impl BooleanBitfield { previous } - /// Returns the index of the highest set bit. Some(n) if some bit is set, None otherwise. - pub fn highest_set_bit(&self) -> Option { - self.0.iter().rposition(|bit| bit) - } - /// Returns the number of bits in this bitfield. pub fn len(&self) -> usize { self.0.len() @@ -115,12 +116,6 @@ impl BooleanBitfield { self.0.iter().filter(|&bit| bit).count() } - /// Returns a vector of bytes representing the bitfield - /// Note that this returns the bit layout of the underlying implementation in the `bit-vec` crate. - pub fn to_bytes(&self) -> Vec { - self.0.to_bytes() - } - /// Compute the intersection (binary-and) of this bitfield with another. Lengths must match. pub fn intersection(&self, other: &Self) -> Self { let mut res = self.clone(); @@ -199,73 +194,106 @@ impl std::ops::BitOr for BooleanBitfield { } } -impl Encodable for BooleanBitfield { - // ssz_append encodes Self according to the `ssz` spec. - fn ssz_append(&self, s: &mut ssz::SszStream) { - s.append_vec(&self.to_bytes()) +impl Encode for BooleanBitfield { + fn is_ssz_fixed_len() -> bool { + false + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.append(&mut self.to_bytes()) } } -impl Decodable for BooleanBitfield { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), ssz::DecodeError> { - let len = ssz::decode::decode_length(bytes, index, ssz::LENGTH_BYTES)?; - if (ssz::LENGTH_BYTES + len) > bytes.len() { - return Err(ssz::DecodeError::TooShort); - } - - if len == 0 { - Ok((BooleanBitfield::new(), index + ssz::LENGTH_BYTES)) - } else { - let bytes = &bytes[(index + 4)..(index + len + 4)]; - - let count = len * 8; - let mut field = BooleanBitfield::with_capacity(count); - for (byte_index, byte) in bytes.iter().enumerate() { - for i in 0..8 { - let bit = byte & (128 >> i); - if bit != 0 { - field.set(8 * byte_index + i, true); - } - } - } - - let index = index + ssz::LENGTH_BYTES + len; - Ok((field, index)) - } +impl Decode for BooleanBitfield { + fn is_ssz_fixed_len() -> bool { + false } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + Ok(BooleanBitfield::from_bytes(bytes)) + } +} + +// Reverse the bit order of a whole byte vec, so that the ith bit +// of the input vec is placed in the (N - i)th bit of the output vec. +// This function is necessary for converting bitfields to and from YAML, +// as the BitVec library and the hex-parser use opposing bit orders. +fn reverse_bit_order(mut bytes: Vec) -> Vec { + bytes.reverse(); + bytes.into_iter().map(LookupReverse::swap_bits).collect() } impl Serialize for BooleanBitfield { - /// Serde serialization is compliant the Ethereum YAML test format. + /// Serde serialization is compliant with the Ethereum YAML test format. fn serialize(&self, serializer: S) -> Result where S: Serializer, { - serializer.serialize_str(&encode(&self.to_bytes())) + serializer.serialize_str(&encode(self.to_bytes())) } } impl<'de> Deserialize<'de> for BooleanBitfield { - /// Serde serialization is compliant the Ethereum YAML test format. + /// Serde serialization is compliant with the Ethereum YAML test format. fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { + // We reverse the bit-order so that the BitVec library can read its 0th + // bit from the end of the hex string, e.g. + // "0xef01" => [0xef, 0x01] => [0b1000_0000, 0b1111_1110] let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; Ok(BooleanBitfield::from_bytes(&bytes)) } } -impl ssz::TreeHash for BooleanBitfield { - fn hash_tree_root(&self) -> Vec { - self.to_bytes().hash_tree_root() +impl tree_hash::TreeHash for BooleanBitfield { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::List + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("List should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("List should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + self.to_bytes().tree_hash_root() } } +cached_tree_hash_bytes_as_list!(BooleanBitfield); + #[cfg(test)] mod tests { use super::*; - use ssz::{decode, ssz_encode, SszStream}; + use serde_yaml; + use ssz::ssz_encode; + use tree_hash::TreeHash; + + #[test] + pub fn test_cached_tree_hash() { + let original = BooleanBitfield::from_bytes(&vec![18; 12][..]); + + let mut cache = cached_tree_hash::TreeHashCache::new(&original).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + original.tree_hash_root() + ); + + let modified = BooleanBitfield::from_bytes(&vec![2; 1][..]); + + cache.update(&modified).unwrap(); + + assert_eq!( + cache.tree_hash_root().unwrap().to_vec(), + modified.tree_hash_root() + ); + } #[test] fn test_new_bitfield() { @@ -312,7 +340,7 @@ mod tests { assert_eq!(field.num_set_bits(), 100); } - const INPUT: &[u8] = &[0b0000_0010, 0b0000_0010]; + const INPUT: &[u8] = &[0b0100_0000, 0b0100_0000]; #[test] fn test_get_from_bitfield() { @@ -338,18 +366,6 @@ mod tests { assert!(!previous); } - #[test] - fn test_highest_set_bit() { - let field = BooleanBitfield::from_bytes(INPUT); - assert_eq!(field.highest_set_bit().unwrap(), 14); - - let field = BooleanBitfield::from_bytes(&[0b0000_0011]); - assert_eq!(field.highest_set_bit().unwrap(), 7); - - let field = BooleanBitfield::new(); - assert_eq!(field.highest_set_bit(), None); - } - #[test] fn test_len() { let field = BooleanBitfield::from_bytes(INPUT); @@ -430,15 +446,17 @@ mod tests { #[test] fn test_ssz_encode() { let field = create_test_bitfield(); - - let mut stream = SszStream::new(); - stream.append(&field); - assert_eq!(stream.drain(), vec![2, 0, 0, 0, 225, 192]); + assert_eq!(field.as_ssz_bytes(), vec![0b0000_0011, 0b1000_0111]); let field = BooleanBitfield::from_elem(18, true); - let mut stream = SszStream::new(); - stream.append(&field); - assert_eq!(stream.drain(), vec![3, 0, 0, 0, 255, 255, 192]); + assert_eq!( + field.as_ssz_bytes(), + vec![0b0000_0011, 0b1111_1111, 0b1111_1111] + ); + + let mut b = BooleanBitfield::new(); + b.set(1, true); + assert_eq!(ssz_encode(&b), vec![0b0000_0010]); } fn create_test_bitfield() -> BooleanBitfield { @@ -454,22 +472,43 @@ mod tests { #[test] fn test_ssz_decode() { - let encoded = vec![2, 0, 0, 0, 225, 192]; - let field = decode::(&encoded).unwrap(); + let encoded = vec![0b0000_0011, 0b1000_0111]; + let field = BooleanBitfield::from_ssz_bytes(&encoded).unwrap(); let expected = create_test_bitfield(); assert_eq!(field, expected); - let encoded = vec![3, 0, 0, 0, 255, 255, 3]; - let field = decode::(&encoded).unwrap(); + let encoded = vec![255, 255, 3]; + let field = BooleanBitfield::from_ssz_bytes(&encoded).unwrap(); let expected = BooleanBitfield::from_bytes(&[255, 255, 3]); assert_eq!(field, expected); } + #[test] + fn test_serialize_deserialize() { + use serde_yaml::Value; + + let data: &[(_, &[_])] = &[ + ("0x01", &[0b00000001]), + ("0xf301", &[0b11110011, 0b00000001]), + ]; + for (hex_data, bytes) in data { + let bitfield = BooleanBitfield::from_bytes(bytes); + assert_eq!( + serde_yaml::from_str::(hex_data).unwrap(), + bitfield + ); + assert_eq!( + serde_yaml::to_value(&bitfield).unwrap(), + Value::String(hex_data.to_string()) + ); + } + } + #[test] fn test_ssz_round_trip() { let original = BooleanBitfield::from_bytes(&vec![18; 12][..]); let ssz = ssz_encode(&original); - let decoded = decode::(&ssz).unwrap(); + let decoded = BooleanBitfield::from_ssz_bytes(&ssz).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/cached_tree_hash/Cargo.toml b/eth2/utils/cached_tree_hash/Cargo.toml new file mode 100644 index 000000000..7b331ad68 --- /dev/null +++ b/eth2/utils/cached_tree_hash/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "cached_tree_hash" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[[bench]] +name = "benches" +harness = false + +[dev-dependencies] +criterion = "0.2" +tree_hash_derive = { path = "../tree_hash_derive" } + +[dependencies] +tree_hash = { path = "../tree_hash" } +ethereum-types = "0.5" +hashing = { path = "../hashing" } +int_to_bytes = { path = "../int_to_bytes" } diff --git a/eth2/utils/cached_tree_hash/README.md b/eth2/utils/cached_tree_hash/README.md new file mode 100644 index 000000000..0498bfc3e --- /dev/null +++ b/eth2/utils/cached_tree_hash/README.md @@ -0,0 +1,76 @@ +# Tree hashing + +Provides both cached and non-cached tree hashing methods. + +## Standard Tree Hash + +```rust +use tree_hash_derive::TreeHash; + +#[derive(TreeHash)] +struct Foo { + a: u64, + b: Vec, +} + +fn main() { + let foo = Foo { + a: 42, + b: vec![1, 2, 3] + }; + + println!("root: {}", foo.tree_hash_root()); +} +``` + +## Cached Tree Hash + + +```rust +use tree_hash_derive::{TreeHash, CachedTreeHash}; + +#[derive(TreeHash, CachedTreeHash)] +struct Foo { + a: u64, + b: Vec, +} + +#[derive(TreeHash, CachedTreeHash)] +struct Bar { + a: Vec, + b: u64, +} + +fn main() { + let bar = Bar { + a: vec![ + Foo { + a: 42, + b: vec![1, 2, 3] + } + ], + b: 42 + }; + + let modified_bar = Bar { + a: vec![ + Foo { + a: 100, + b: vec![1, 2, 3, 4, 5, 6] + }, + Foo { + a: 42, + b: vec![] + } + ], + b: 99 + }; + + + let mut hasher = CachedTreeHasher::new(&bar).unwrap(); + hasher.update(&modified_bar).unwrap(); + + // Assert that the cached tree hash matches a standard tree hash. + assert_eq!(hasher.tree_hash_root(), modified_bar.tree_hash_root()); +} +``` diff --git a/eth2/utils/cached_tree_hash/benches/benches.rs b/eth2/utils/cached_tree_hash/benches/benches.rs new file mode 100644 index 000000000..be7e26bb5 --- /dev/null +++ b/eth2/utils/cached_tree_hash/benches/benches.rs @@ -0,0 +1,73 @@ +#[macro_use] +extern crate criterion; + +use cached_tree_hash::TreeHashCache; +use criterion::black_box; +use criterion::{Benchmark, Criterion}; +use ethereum_types::H256 as Hash256; +use hashing::hash; +use tree_hash::TreeHash; + +fn criterion_benchmark(c: &mut Criterion) { + let n = 1024; + + let source_vec: Vec = (0..n).map(|_| Hash256::random()).collect(); + + let mut source_modified_vec = source_vec.clone(); + source_modified_vec[n - 1] = Hash256::random(); + + let modified_vec = source_modified_vec.clone(); + c.bench( + &format!("vec_of_{}_hashes", n), + Benchmark::new("standard", move |b| { + b.iter_with_setup( + || modified_vec.clone(), + |modified_vec| black_box(modified_vec.tree_hash_root()), + ) + }) + .sample_size(100), + ); + + let modified_vec = source_modified_vec.clone(); + c.bench( + &format!("vec_of_{}_hashes", n), + Benchmark::new("build_cache", move |b| { + b.iter_with_setup( + || modified_vec.clone(), + |vec| black_box(TreeHashCache::new(&vec, 0)), + ) + }) + .sample_size(100), + ); + + let vec = source_vec.clone(); + let modified_vec = source_modified_vec.clone(); + c.bench( + &format!("vec_of_{}_hashes", n), + Benchmark::new("cache_update", move |b| { + b.iter_with_setup( + || { + let cache = TreeHashCache::new(&vec, 0).unwrap(); + (cache, modified_vec.clone()) + }, + |(mut cache, modified_vec)| black_box(cache.update(&modified_vec)), + ) + }) + .sample_size(100), + ); + + c.bench( + &format!("{}_hashes", n), + Benchmark::new("hash_64_bytes", move |b| { + b.iter(|| { + for _ in 0..n { + let _digest = hash(&[42; 64]); + } + }) + }) + .sample_size(100), + ); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/eth2/utils/cached_tree_hash/examples/8k_hashes_cached.rs b/eth2/utils/cached_tree_hash/examples/8k_hashes_cached.rs new file mode 100644 index 000000000..1e67571d5 --- /dev/null +++ b/eth2/utils/cached_tree_hash/examples/8k_hashes_cached.rs @@ -0,0 +1,21 @@ +use cached_tree_hash::TreeHashCache; +use ethereum_types::H256 as Hash256; + +fn run(vec: &Vec, modified_vec: &Vec) { + let mut cache = TreeHashCache::new(vec).unwrap(); + + cache.update(modified_vec).unwrap(); +} + +fn main() { + let n = 2048; + + let vec: Vec = (0..n).map(|_| Hash256::random()).collect(); + + let mut modified_vec = vec.clone(); + modified_vec[n - 1] = Hash256::random(); + + for _ in 0..10_000 { + run(&vec, &modified_vec); + } +} diff --git a/eth2/utils/cached_tree_hash/examples/8k_hashes_standard.rs b/eth2/utils/cached_tree_hash/examples/8k_hashes_standard.rs new file mode 100644 index 000000000..bcbb392e2 --- /dev/null +++ b/eth2/utils/cached_tree_hash/examples/8k_hashes_standard.rs @@ -0,0 +1,10 @@ +use ethereum_types::H256 as Hash256; +use tree_hash::TreeHash; + +fn main() { + let n = 2048; + + let vec: Vec = (0..n).map(|_| Hash256::random()).collect(); + + vec.tree_hash_root(); +} diff --git a/eth2/utils/cached_tree_hash/src/btree_overlay.rs b/eth2/utils/cached_tree_hash/src/btree_overlay.rs new file mode 100644 index 000000000..5692a4391 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/btree_overlay.rs @@ -0,0 +1,340 @@ +use super::*; + +/// A schema defining a binary tree over a `TreeHashCache`. +/// +/// This structure is used for succinct storage; run-time functionality is gained by converting a +/// `BTreeSchema` into a `BTreeOverlay`. +#[derive(Debug, PartialEq, Clone)] +pub struct BTreeSchema { + /// The depth of a schema defines how far it is nested within other fixed-length items. + /// + /// Each time a new variable-length object is created all items within it are assigned a depth + /// of `depth + 1`. + /// + /// When storing the schemas in a list, the depth parameter allows for removing all schemas + /// belonging to a specific variable-length item without removing schemas related to adjacent + /// variable-length items. + pub depth: usize, + lengths: Vec, +} + +impl BTreeSchema { + pub fn from_lengths(depth: usize, lengths: Vec) -> Self { + Self { depth, lengths } + } + + pub fn into_overlay(self, offset: usize) -> BTreeOverlay { + BTreeOverlay::from_schema(self, offset) + } +} + +impl Into for BTreeOverlay { + fn into(self) -> BTreeSchema { + BTreeSchema { + depth: self.depth, + lengths: self.lengths, + } + } +} + +/// Provides a status for some leaf-node in binary tree. +#[derive(Debug, PartialEq, Clone)] +pub enum LeafNode { + /// The leaf node does not exist in this tree. + DoesNotExist, + /// The leaf node exists in the tree and has a real value within the given `chunk` range. + Exists(Range), + /// The leaf node exists in the tree only as padding. + Padding, +} + +/// Instantiated from a `BTreeSchema`, a `BTreeOverlay` allows for interpreting some +/// non-consecutive chunks of a `TreeHashCache` as a perfect binary tree. +/// +/// The primary purpose of this struct is to map from binary tree "nodes" to `TreeHashCache` +/// "chunks". Each tree has nodes `0..n` where `n` is the number of nodes and `0` is the root node. +/// Each of these nodes is mapped to a chunk, starting from `self.offset` and increasing in steps +/// of `1` for internal nodes and arbitrary steps for leaf-nodes. +#[derive(Debug, PartialEq, Clone)] +pub struct BTreeOverlay { + offset: usize, + /// See `BTreeSchema.depth` for a description. + pub depth: usize, + lengths: Vec, +} + +impl BTreeOverlay { + /// Instantiates a new instance for `item`, where it's first chunk is `inital_offset` and has + /// the specified `depth`. + pub fn new(item: &T, initial_offset: usize, depth: usize) -> Self + where + T: CachedTreeHash, + { + Self::from_schema(item.tree_hash_cache_schema(depth), initial_offset) + } + + /// Instantiates a new instance from a schema, where it's first chunk is `offset`. + pub fn from_schema(schema: BTreeSchema, offset: usize) -> Self { + Self { + offset, + depth: schema.depth, + lengths: schema.lengths, + } + } + + /// Returns a `LeafNode` for each of the `n` leaves of the tree. + /// + /// `LeafNode::DoesNotExist` is returned for each element `i` in `0..n` where `i >= + /// self.num_leaf_nodes()`. + pub fn get_leaf_nodes(&self, n: usize) -> Vec { + let mut running_offset = self.offset + self.num_internal_nodes(); + + let mut leaf_nodes: Vec = self + .lengths + .iter() + .map(|length| { + let range = running_offset..running_offset + length; + running_offset += length; + LeafNode::Exists(range) + }) + .collect(); + + leaf_nodes.resize(self.num_leaf_nodes(), LeafNode::Padding); + leaf_nodes.resize(n, LeafNode::DoesNotExist); + + leaf_nodes + } + + /// Returns the number of leaf nodes in the tree. + pub fn num_leaf_nodes(&self) -> usize { + self.lengths.len().next_power_of_two() + } + + /// Returns the number of leafs in the tree which are padding. + pub fn num_padding_leaves(&self) -> usize { + self.num_leaf_nodes() - self.lengths.len() + } + + /// Returns the number of nodes in the tree. + /// + /// Note: this is distinct from `num_chunks`, which returns the total number of chunks in + /// this tree. + pub fn num_nodes(&self) -> usize { + 2 * self.num_leaf_nodes() - 1 + } + + /// Returns the number of internal (non-leaf) nodes in the tree. + pub fn num_internal_nodes(&self) -> usize { + self.num_leaf_nodes() - 1 + } + + /// Returns the chunk of the first node of the tree. + fn first_node(&self) -> usize { + self.offset + } + + /// Returns the root chunk of the tree (the zero-th node) + pub fn root(&self) -> usize { + self.first_node() + } + + /// Returns the first chunk outside of the boundary of this tree. It is the root node chunk + /// plus the total number of chunks in the tree. + pub fn next_node(&self) -> usize { + self.first_node() + self.num_internal_nodes() + self.num_leaf_nodes() - self.lengths.len() + + self.lengths.iter().sum::() + } + + /// Returns the height of the tree where a tree with a single node has a height of 1. + pub fn height(&self) -> usize { + self.num_leaf_nodes().trailing_zeros() as usize + } + + /// Returns the range of chunks that belong to the internal nodes of the tree. + pub fn internal_chunk_range(&self) -> Range { + self.offset..self.offset + self.num_internal_nodes() + } + + /// Returns all of the chunks that are encompassed by the tree. + pub fn chunk_range(&self) -> Range { + self.first_node()..self.next_node() + } + + /// Returns the number of chunks inside this tree (including subtrees). + /// + /// Note: this is distinct from `num_nodes` which returns the number of nodes in the binary + /// tree. + pub fn num_chunks(&self) -> usize { + self.next_node() - self.first_node() + } + + /// Returns the first chunk of the first leaf node in the tree. + pub fn first_leaf_node(&self) -> usize { + self.offset + self.num_internal_nodes() + } + + /// Returns the chunks for some given parent node. + /// + /// Note: it is a parent _node_ not a parent _chunk_. + pub fn child_chunks(&self, parent: usize) -> (usize, usize) { + let children = children(parent); + + if children.1 < self.num_internal_nodes() { + (children.0 + self.offset, children.1 + self.offset) + } else { + let chunks = self.n_leaf_node_chunks(children.1); + (chunks[chunks.len() - 2], chunks[chunks.len() - 1]) + } + } + + /// Returns a vec of (parent_chunk, (left_child_chunk, right_child_chunk)). + pub fn internal_parents_and_children(&self) -> Vec<(usize, (usize, usize))> { + let mut chunks = Vec::with_capacity(self.num_nodes()); + chunks.append(&mut self.internal_node_chunks()); + chunks.append(&mut self.leaf_node_chunks()); + + (0..self.num_internal_nodes()) + .map(|parent| { + let children = children(parent); + (chunks[parent], (chunks[children.0], chunks[children.1])) + }) + .collect() + } + + /// Returns a vec of chunk indices for each internal node of the tree. + pub fn internal_node_chunks(&self) -> Vec { + (self.offset..self.offset + self.num_internal_nodes()).collect() + } + + /// Returns a vec of the first chunk for each leaf node of the tree. + pub fn leaf_node_chunks(&self) -> Vec { + self.n_leaf_node_chunks(self.num_leaf_nodes()) + } + + /// Returns a vec of the first chunk index for the first `n` leaf nodes of the tree. + fn n_leaf_node_chunks(&self, n: usize) -> Vec { + let mut chunks = Vec::with_capacity(n); + + let mut chunk = self.offset + self.num_internal_nodes(); + for i in 0..n { + chunks.push(chunk); + + match self.lengths.get(i) { + Some(len) => { + chunk += len; + } + None => chunk += 1, + } + } + + chunks + } +} + +fn children(parent: usize) -> (usize, usize) { + ((2 * parent + 1), (2 * parent + 2)) +} + +#[cfg(test)] +mod test { + use super::*; + + fn get_tree_a(n: usize) -> BTreeOverlay { + BTreeSchema::from_lengths(0, vec![1; n]).into_overlay(0) + } + + #[test] + fn leaf_node_chunks() { + let tree = get_tree_a(4); + + assert_eq!(tree.leaf_node_chunks(), vec![3, 4, 5, 6]) + } + + #[test] + fn internal_node_chunks() { + let tree = get_tree_a(4); + + assert_eq!(tree.internal_node_chunks(), vec![0, 1, 2]) + } + + #[test] + fn internal_parents_and_children() { + let tree = get_tree_a(4); + + assert_eq!( + tree.internal_parents_and_children(), + vec![(0, (1, 2)), (1, (3, 4)), (2, (5, 6))] + ) + } + + #[test] + fn chunk_range() { + let tree = get_tree_a(4); + assert_eq!(tree.chunk_range(), 0..7); + + let tree = get_tree_a(1); + assert_eq!(tree.chunk_range(), 0..1); + + let tree = get_tree_a(2); + assert_eq!(tree.chunk_range(), 0..3); + + let tree = BTreeSchema::from_lengths(0, vec![1, 1]).into_overlay(11); + assert_eq!(tree.chunk_range(), 11..14); + + let tree = BTreeSchema::from_lengths(0, vec![7, 7, 7]).into_overlay(0); + assert_eq!(tree.chunk_range(), 0..25); + } + + #[test] + fn get_leaf_node() { + let tree = get_tree_a(4); + let leaves = tree.get_leaf_nodes(5); + + assert_eq!(leaves[0], LeafNode::Exists(3..4)); + assert_eq!(leaves[1], LeafNode::Exists(4..5)); + assert_eq!(leaves[2], LeafNode::Exists(5..6)); + assert_eq!(leaves[3], LeafNode::Exists(6..7)); + assert_eq!(leaves[4], LeafNode::DoesNotExist); + + let tree = get_tree_a(3); + let leaves = tree.get_leaf_nodes(5); + + assert_eq!(leaves[0], LeafNode::Exists(3..4)); + assert_eq!(leaves[1], LeafNode::Exists(4..5)); + assert_eq!(leaves[2], LeafNode::Exists(5..6)); + assert_eq!(leaves[3], LeafNode::Padding); + assert_eq!(leaves[4], LeafNode::DoesNotExist); + + let tree = get_tree_a(0); + let leaves = tree.get_leaf_nodes(2); + + assert_eq!(leaves[0], LeafNode::Padding); + assert_eq!(leaves[1], LeafNode::DoesNotExist); + + let tree = BTreeSchema::from_lengths(0, vec![3]).into_overlay(0); + let leaves = tree.get_leaf_nodes(2); + assert_eq!(leaves[0], LeafNode::Exists(0..3)); + assert_eq!(leaves[1], LeafNode::DoesNotExist); + + let tree = BTreeSchema::from_lengths(0, vec![3]).into_overlay(10); + let leaves = tree.get_leaf_nodes(2); + assert_eq!(leaves[0], LeafNode::Exists(10..13)); + assert_eq!(leaves[1], LeafNode::DoesNotExist); + } + + #[test] + fn root_of_one_node() { + let tree = get_tree_a(1); + + assert_eq!(tree.root(), 0); + assert_eq!(tree.num_internal_nodes(), 0); + assert_eq!(tree.num_leaf_nodes(), 1); + } + + #[test] + fn child_chunks() { + let tree = get_tree_a(4); + + assert_eq!(tree.child_chunks(0), (1, 2)) + } +} diff --git a/eth2/utils/cached_tree_hash/src/errors.rs b/eth2/utils/cached_tree_hash/src/errors.rs new file mode 100644 index 000000000..d9ac02913 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/errors.rs @@ -0,0 +1,19 @@ +use tree_hash::TreeHashType; + +#[derive(Debug, PartialEq, Clone)] +pub enum Error { + ShouldNotProduceBTreeOverlay, + NoFirstNode, + NoBytesForRoot, + UnableToObtainSlices, + UnableToGrowMerkleTree, + UnableToShrinkMerkleTree, + TreeCannotHaveZeroNodes, + CacheNotInitialized, + ShouldNeverBePacked(TreeHashType), + BytesAreNotEvenChunks(usize), + NoModifiedFieldForChunk(usize), + NoBytesForChunk(usize), + NoSchemaForIndex(usize), + NotLeafNode(usize), +} diff --git a/eth2/utils/cached_tree_hash/src/impls.rs b/eth2/utils/cached_tree_hash/src/impls.rs new file mode 100644 index 000000000..5105ad6a7 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/impls.rs @@ -0,0 +1,110 @@ +use super::*; +use crate::merkleize::merkleize; +use ethereum_types::H256; + +pub mod vec; + +macro_rules! impl_for_single_leaf_int { + ($type: ident) => { + impl CachedTreeHash for $type { + fn new_tree_hash_cache(&self, _depth: usize) -> Result { + Ok(TreeHashCache::from_bytes( + merkleize(self.to_le_bytes().to_vec()), + false, + None, + )?) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema { + BTreeSchema::from_lengths(depth, vec![1]) + } + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> { + let leaf = merkleize(self.to_le_bytes().to_vec()); + cache.maybe_update_chunk(cache.chunk_index, &leaf)?; + + cache.chunk_index += 1; + + Ok(()) + } + } + }; +} + +impl_for_single_leaf_int!(u8); +impl_for_single_leaf_int!(u16); +impl_for_single_leaf_int!(u32); +impl_for_single_leaf_int!(u64); +impl_for_single_leaf_int!(usize); + +impl CachedTreeHash for bool { + fn new_tree_hash_cache(&self, _depth: usize) -> Result { + Ok(TreeHashCache::from_bytes( + merkleize((*self as u8).to_le_bytes().to_vec()), + false, + None, + )?) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema { + BTreeSchema::from_lengths(depth, vec![1]) + } + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> { + let leaf = merkleize((*self as u8).to_le_bytes().to_vec()); + cache.maybe_update_chunk(cache.chunk_index, &leaf)?; + + cache.chunk_index += 1; + + Ok(()) + } +} + +impl CachedTreeHash for [u8; 4] { + fn new_tree_hash_cache(&self, _depth: usize) -> Result { + Ok(TreeHashCache::from_bytes( + merkleize(self.to_vec()), + false, + None, + )?) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema { + BTreeSchema::from_lengths(depth, vec![1]) + } + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> { + let leaf = merkleize(self.to_vec()); + cache.maybe_update_chunk(cache.chunk_index, &leaf)?; + + cache.chunk_index += 1; + + Ok(()) + } +} + +impl CachedTreeHash for H256 { + fn new_tree_hash_cache(&self, _depth: usize) -> Result { + Ok(TreeHashCache::from_bytes( + self.as_bytes().to_vec(), + false, + None, + )?) + } + + fn num_tree_hash_cache_chunks(&self) -> usize { + 1 + } + + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema { + BTreeSchema::from_lengths(depth, vec![1]) + } + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> { + cache.maybe_update_chunk(cache.chunk_index, self.as_bytes())?; + + cache.chunk_index += 1; + + Ok(()) + } +} diff --git a/eth2/utils/cached_tree_hash/src/impls/vec.rs b/eth2/utils/cached_tree_hash/src/impls/vec.rs new file mode 100644 index 000000000..bdb7eb134 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/impls/vec.rs @@ -0,0 +1,338 @@ +use super::*; +use crate::btree_overlay::LeafNode; +use crate::merkleize::{merkleize, num_sanitized_leaves, sanitise_bytes}; + +macro_rules! impl_for_list { + ($type: ty) => { + impl CachedTreeHash for $type + where + T: CachedTreeHash + TreeHash, + { + fn new_tree_hash_cache(&self, depth: usize) -> Result { + let (mut cache, schema) = new_tree_hash_cache(self, depth)?; + + cache.add_length_nodes(schema.into_overlay(0).chunk_range(), self.len())?; + + Ok(cache) + } + + fn num_tree_hash_cache_chunks(&self) -> usize { + // Add two extra nodes to cater for the node before and after to allow mixing-in length. + BTreeOverlay::new(self, 0, 0).num_chunks() + 2 + } + + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema { + produce_schema(self, depth) + } + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> { + // Skip the length-mixed-in root node. + cache.chunk_index += 1; + + // Update the cache, returning the new overlay. + let new_overlay = update_tree_hash_cache(&self, cache)?; + + // Mix in length + cache.mix_in_length(new_overlay.chunk_range(), self.len())?; + + // Skip an extra node to clear the length node. + cache.chunk_index += 1; + + Ok(()) + } + } + }; +} + +impl_for_list!(Vec); +impl_for_list!(&[T]); + +/// Build a new tree hash cache for some slice. +/// +/// Valid for both variable- and fixed-length slices. Does _not_ mix-in the length of the list, +/// the caller must do this. +pub fn new_tree_hash_cache( + vec: &[T], + depth: usize, +) -> Result<(TreeHashCache, BTreeSchema), Error> { + let schema = vec.tree_hash_cache_schema(depth); + + let cache = match T::tree_hash_type() { + TreeHashType::Basic => TreeHashCache::from_bytes( + merkleize(get_packed_leaves(vec)?), + false, + Some(schema.clone()), + ), + TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => { + let subtrees = vec + .iter() + .map(|item| TreeHashCache::new_at_depth(item, depth + 1)) + .collect::, _>>()?; + + TreeHashCache::from_subtrees(&vec, subtrees, depth) + } + }?; + + Ok((cache, schema)) +} + +/// Produce a schema for some slice. +/// +/// Valid for both variable- and fixed-length slices. Does _not_ add the mix-in length nodes, the +/// caller must do this. +pub fn produce_schema(vec: &[T], depth: usize) -> BTreeSchema { + let lengths = match T::tree_hash_type() { + TreeHashType::Basic => { + // Ceil division. + let num_leaves = + (vec.len() + T::tree_hash_packing_factor() - 1) / T::tree_hash_packing_factor(); + + // Disallow zero-length as an empty list still has one all-padding node. + vec![1; std::cmp::max(1, num_leaves)] + } + TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => { + let mut lengths = vec![]; + + for item in vec { + lengths.push(item.num_tree_hash_cache_chunks()) + } + + lengths + } + }; + + BTreeSchema::from_lengths(depth, lengths) +} + +/// Updates the cache for some slice. +/// +/// Valid for both variable- and fixed-length slices. Does _not_ cater for the mix-in length nodes, +/// the caller must do this. +#[allow(clippy::range_plus_one)] // Minor readability lint requiring structural changes; not worth it. +pub fn update_tree_hash_cache( + vec: &[T], + cache: &mut TreeHashCache, +) -> Result { + let old_overlay = cache.get_overlay(cache.schema_index, cache.chunk_index)?; + let new_overlay = BTreeOverlay::new(&vec, cache.chunk_index, old_overlay.depth); + + cache.replace_overlay(cache.schema_index, cache.chunk_index, new_overlay.clone())?; + + cache.schema_index += 1; + + match T::tree_hash_type() { + TreeHashType::Basic => { + let mut buf = vec![0; HASHSIZE]; + let item_bytes = HASHSIZE / T::tree_hash_packing_factor(); + + // If the number of leaf nodes has changed, resize the cache. + if new_overlay.num_leaf_nodes() < old_overlay.num_leaf_nodes() { + let start = new_overlay.next_node(); + let end = start + (old_overlay.num_leaf_nodes() - new_overlay.num_leaf_nodes()); + + cache.splice(start..end, vec![], vec![]); + } else if new_overlay.num_leaf_nodes() > old_overlay.num_leaf_nodes() { + let start = old_overlay.next_node(); + let new_nodes = new_overlay.num_leaf_nodes() - old_overlay.num_leaf_nodes(); + + cache.splice( + start..start, + vec![0; new_nodes * HASHSIZE], + vec![true; new_nodes], + ); + } + + // Iterate through each of the leaf nodes in the new list. + for i in 0..new_overlay.num_leaf_nodes() { + // Iterate through the number of items that may be packing into the leaf node. + for j in 0..T::tree_hash_packing_factor() { + // Create a mut slice that can be filled with either a serialized item or + // padding. + let buf_slice = &mut buf[j * item_bytes..(j + 1) * item_bytes]; + + // Attempt to get the item for this portion of the chunk. If it exists, + // update `buf` with it's serialized bytes. If it doesn't exist, update + // `buf` with padding. + match vec.get(i * T::tree_hash_packing_factor() + j) { + Some(item) => { + buf_slice.copy_from_slice(&item.tree_hash_packed_encoding()); + } + None => buf_slice.copy_from_slice(&vec![0; item_bytes]), + } + } + + // Update the chunk if the generated `buf` is not the same as the cache. + let chunk = new_overlay.first_leaf_node() + i; + cache.maybe_update_chunk(chunk, &buf)?; + } + } + TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => { + let longest_len = + std::cmp::max(new_overlay.num_leaf_nodes(), old_overlay.num_leaf_nodes()); + + let old_leaf_nodes = old_overlay.get_leaf_nodes(longest_len); + let new_leaf_nodes = if old_overlay == new_overlay { + old_leaf_nodes.clone() + } else { + new_overlay.get_leaf_nodes(longest_len) + }; + + for i in 0..longest_len { + match (&old_leaf_nodes[i], &new_leaf_nodes[i]) { + // The item existed in the previous list and exists in the current list. + // + // Update the item. + (LeafNode::Exists(_old), LeafNode::Exists(new)) => { + cache.chunk_index = new.start; + + vec[i].update_tree_hash_cache(cache)?; + } + // The list has been lengthened and this is a new item that did not exist in + // the previous list. + // + // Splice the tree for the new item into the current chunk_index. + (LeafNode::DoesNotExist, LeafNode::Exists(new)) => { + splice_in_new_tree( + &vec[i], + new.start..new.start, + new_overlay.depth + 1, + cache, + )?; + + cache.chunk_index = new.end; + } + // The list has been lengthened and this is a new item that was prevously a + // padding item. + // + // Splice the tree for the new item over the padding chunk. + (LeafNode::Padding, LeafNode::Exists(new)) => { + splice_in_new_tree( + &vec[i], + new.start..new.start + 1, + new_overlay.depth + 1, + cache, + )?; + + cache.chunk_index = new.end; + } + // The list has been shortened and this item was removed from the list and made + // into padding. + // + // Splice a padding node over the number of nodes the previous item occupied, + // starting at the current chunk_index. + (LeafNode::Exists(old), LeafNode::Padding) => { + let num_chunks = old.end - old.start; + + cache.splice( + cache.chunk_index..cache.chunk_index + num_chunks, + vec![0; HASHSIZE], + vec![true], + ); + + cache.chunk_index += 1; + } + // The list has been shortened and the item for this leaf existed in the + // previous list, but does not exist in this list. + // + // Remove the number of nodes the previous item occupied, starting at the + // current chunk_index. + (LeafNode::Exists(old), LeafNode::DoesNotExist) => { + let num_chunks = old.end - old.start; + + cache.splice( + cache.chunk_index..cache.chunk_index + num_chunks, + vec![], + vec![], + ); + } + // The list has been shortened and this leaf was padding in the previous list, + // however it should not exist in this list. + // + // Remove one node, starting at the current `chunk_index`. + (LeafNode::Padding, LeafNode::DoesNotExist) => { + cache.splice(cache.chunk_index..cache.chunk_index + 1, vec![], vec![]); + } + // The list has been lengthened and this leaf did not exist in the previous + // list, but should be padding for this list. + // + // Splice in a new padding node at the current chunk_index. + (LeafNode::DoesNotExist, LeafNode::Padding) => { + cache.splice( + cache.chunk_index..cache.chunk_index, + vec![0; HASHSIZE], + vec![true], + ); + + cache.chunk_index += 1; + } + // This leaf was padding in both lists, there's nothing to do. + (LeafNode::Padding, LeafNode::Padding) => (), + // As we are looping through the larger of the lists of leaf nodes, it should + // be impossible for either leaf to be non-existant. + (LeafNode::DoesNotExist, LeafNode::DoesNotExist) => unreachable!(), + } + } + + // Clean out any excess schemas that may or may not be remaining if the list was + // shortened. + cache.remove_proceeding_child_schemas(cache.schema_index, new_overlay.depth); + } + } + + cache.update_internal_nodes(&new_overlay)?; + + cache.chunk_index = new_overlay.next_node(); + + Ok(new_overlay) +} + +/// Create a new `TreeHashCache` from `item` and splice it over the `chunks_to_replace` chunks of +/// the given `cache`. +/// +/// Useful for the case where a new element is added to a list. +/// +/// The schemas created for `item` will have the given `depth`. +fn splice_in_new_tree( + item: &T, + chunks_to_replace: Range, + depth: usize, + cache: &mut TreeHashCache, +) -> Result<(), Error> +where + T: CachedTreeHash, +{ + let (bytes, mut bools, schemas) = TreeHashCache::new_at_depth(item, depth)?.into_components(); + + // Record the number of schemas, this will be used later in the fn. + let num_schemas = schemas.len(); + + // Flag the root node of the new tree as dirty. + bools[0] = true; + + cache.splice(chunks_to_replace, bytes, bools); + cache + .schemas + .splice(cache.schema_index..cache.schema_index, schemas); + + cache.schema_index += num_schemas; + + Ok(()) +} + +/// Packs all of the leaves of `vec` into a single byte-array, appending `0` to ensure the number +/// of chunks in the byte-array is a power-of-two. +fn get_packed_leaves(vec: &[T]) -> Result, Error> +where + T: CachedTreeHash, +{ + let num_packed_bytes = (BYTES_PER_CHUNK / T::tree_hash_packing_factor()) * vec.len(); + let num_leaves = num_sanitized_leaves(num_packed_bytes); + + let mut packed = Vec::with_capacity(num_leaves * HASHSIZE); + + for item in vec { + packed.append(&mut item.tree_hash_packed_encoding()); + } + + Ok(sanitise_bytes(packed)) +} diff --git a/eth2/utils/cached_tree_hash/src/lib.rs b/eth2/utils/cached_tree_hash/src/lib.rs new file mode 100644 index 000000000..8bc26aa79 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/lib.rs @@ -0,0 +1,150 @@ +//! Performs cached merkle-hashing adhering to the Ethereum 2.0 specification defined +//! [here](https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/simple-serialize.md#merkleization). +//! +//! Caching allows for reduced hashing when some object has only been partially modified, which +//! consumes less CPU-time at the cost of additional storage. For example, +//! determining the root of a list of 1024 items with a single modification has been observed to +//! run in 1/25th of the time of a full merkle hash. +//! +//! +//! # Example: +//! +//! ``` +//! use cached_tree_hash::TreeHashCache; +//! use tree_hash_derive::{TreeHash, CachedTreeHash}; +//! +//! #[derive(TreeHash, CachedTreeHash)] +//! struct Foo { +//! bar: u64, +//! baz: Vec +//! } +//! +//! let mut foo = Foo { +//! bar: 1, +//! baz: vec![0, 1, 2] +//! }; +//! +//! let mut cache = TreeHashCache::new(&foo).unwrap(); +//! +//! foo.baz[1] = 0; +//! +//! cache.update(&foo).unwrap(); +//! +//! println!("Root is: {:?}", cache.tree_hash_root().unwrap()); +//! ``` + +use hashing::hash; +use std::ops::Range; +use tree_hash::{TreeHash, TreeHashType, BYTES_PER_CHUNK, HASHSIZE}; + +mod btree_overlay; +mod errors; +mod impls; +pub mod merkleize; +mod resize; +mod tree_hash_cache; + +pub use btree_overlay::{BTreeOverlay, BTreeSchema}; +pub use errors::Error; +pub use impls::vec; +pub use tree_hash_cache::TreeHashCache; + +pub trait CachedTreeHash: TreeHash { + fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema; + + fn num_tree_hash_cache_chunks(&self) -> usize { + self.tree_hash_cache_schema(0).into_overlay(0).num_chunks() + } + + fn new_tree_hash_cache(&self, depth: usize) -> Result; + + fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error>; +} + +/// Implements `CachedTreeHash` on `$type`, where `$type` is a fixed-length vector and each item in +/// the `$type` is encoded as bytes using `ssz_encode`. +#[macro_export] +macro_rules! cached_tree_hash_ssz_encoding_as_vector { + ($type: ident, $num_bytes: expr) => { + impl cached_tree_hash::CachedTreeHash for $type { + fn new_tree_hash_cache( + &self, + depth: usize, + ) -> Result { + let (cache, _schema) = + cached_tree_hash::vec::new_tree_hash_cache(&ssz::ssz_encode(self), depth)?; + + Ok(cache) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema { + let lengths = + vec![1; cached_tree_hash::merkleize::num_unsanitized_leaves($num_bytes)]; + cached_tree_hash::BTreeSchema::from_lengths(depth, lengths) + } + + fn update_tree_hash_cache( + &self, + cache: &mut cached_tree_hash::TreeHashCache, + ) -> Result<(), cached_tree_hash::Error> { + cached_tree_hash::vec::update_tree_hash_cache(&ssz::ssz_encode(self), cache)?; + + Ok(()) + } + } + }; +} + +/// Implements `CachedTreeHash` on `$type`, where `$type` is a variable-length list and each item +/// in `$type` is encoded as bytes by calling `item.to_bytes()`. +#[macro_export] +macro_rules! cached_tree_hash_bytes_as_list { + ($type: ident) => { + impl cached_tree_hash::CachedTreeHash for $type { + fn new_tree_hash_cache( + &self, + depth: usize, + ) -> Result { + let bytes = self.to_bytes(); + + let (mut cache, schema) = + cached_tree_hash::vec::new_tree_hash_cache(&bytes, depth)?; + + cache.add_length_nodes(schema.into_overlay(0).chunk_range(), bytes.len())?; + + Ok(cache) + } + + fn num_tree_hash_cache_chunks(&self) -> usize { + // Add two extra nodes to cater for the node before and after to allow mixing-in length. + cached_tree_hash::BTreeOverlay::new(self, 0, 0).num_chunks() + 2 + } + + fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema { + let bytes = self.to_bytes(); + cached_tree_hash::vec::produce_schema(&bytes, depth) + } + + fn update_tree_hash_cache( + &self, + cache: &mut cached_tree_hash::TreeHashCache, + ) -> Result<(), cached_tree_hash::Error> { + let bytes = self.to_bytes(); + + // Skip the length-mixed-in root node. + cache.chunk_index += 1; + + // Update the cache, returning the new overlay. + let new_overlay = cached_tree_hash::vec::update_tree_hash_cache(&bytes, cache)?; + + // Mix in length + cache.mix_in_length(new_overlay.chunk_range(), bytes.len())?; + + // Skip an extra node to clear the length node. + cache.chunk_index += 1; + + Ok(()) + } + } + }; +} diff --git a/eth2/utils/cached_tree_hash/src/merkleize.rs b/eth2/utils/cached_tree_hash/src/merkleize.rs new file mode 100644 index 000000000..9d8c83200 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/merkleize.rs @@ -0,0 +1,83 @@ +use hashing::hash; +use tree_hash::{BYTES_PER_CHUNK, HASHSIZE, MERKLE_HASH_CHUNK}; + +/// Split `values` into a power-of-two, identical-length chunks (padding with `0`) and merkleize +/// them, returning the entire merkle tree. +/// +/// The root hash is `merkleize(values)[0..BYTES_PER_CHUNK]`. +pub fn merkleize(values: Vec) -> Vec { + let values = sanitise_bytes(values); + + let leaves = values.len() / HASHSIZE; + + if leaves == 0 { + panic!("No full leaves"); + } + + if !leaves.is_power_of_two() { + panic!("leaves is not power of two"); + } + + let mut o: Vec = vec![0; (num_nodes(leaves) - leaves) * HASHSIZE]; + o.append(&mut values.to_vec()); + + let mut i = o.len(); + let mut j = o.len() - values.len(); + + while i >= MERKLE_HASH_CHUNK { + i -= MERKLE_HASH_CHUNK; + let hash = hash(&o[i..i + MERKLE_HASH_CHUNK]); + + j -= HASHSIZE; + o[j..j + HASHSIZE].copy_from_slice(&hash); + } + + o +} + +/// Ensures that the given `bytes` are a power-of-two chunks, padding with zero if not. +pub fn sanitise_bytes(mut bytes: Vec) -> Vec { + let present_leaves = num_unsanitized_leaves(bytes.len()); + let required_leaves = present_leaves.next_power_of_two(); + + if (present_leaves != required_leaves) | last_leaf_needs_padding(bytes.len()) { + bytes.resize(num_bytes(required_leaves), 0); + } + + bytes +} + +/// Pads out `bytes` to ensure it is a clean `num_leaves` chunks. +pub fn pad_for_leaf_count(num_leaves: usize, bytes: &mut Vec) { + let required_leaves = num_leaves.next_power_of_two(); + + bytes.resize( + bytes.len() + (required_leaves - num_leaves) * BYTES_PER_CHUNK, + 0, + ); +} + +fn last_leaf_needs_padding(num_bytes: usize) -> bool { + num_bytes % HASHSIZE != 0 +} + +/// Returns the number of leaves for a given `bytes_len` number of bytes, rounding up if +/// `num_bytes` is not a client multiple of chunk size. +pub fn num_unsanitized_leaves(bytes_len: usize) -> usize { + (bytes_len + HASHSIZE - 1) / HASHSIZE +} + +fn num_bytes(num_leaves: usize) -> usize { + num_leaves * HASHSIZE +} + +fn num_nodes(num_leaves: usize) -> usize { + 2 * num_leaves - 1 +} + +/// Returns the power-of-two number of leaves that would result from the given `bytes_len` number +/// of bytes. +pub fn num_sanitized_leaves(bytes_len: usize) -> usize { + let leaves = (bytes_len + HASHSIZE - 1) / HASHSIZE; + leaves.next_power_of_two() +} diff --git a/eth2/utils/cached_tree_hash/src/resize.rs b/eth2/utils/cached_tree_hash/src/resize.rs new file mode 100644 index 000000000..5428e234b --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/resize.rs @@ -0,0 +1,223 @@ +#![allow(clippy::range_plus_one)] // Minor readability lint requiring structural changes; not worth it. + +use super::*; + +/// New vec is bigger than old vec. +pub fn grow_merkle_tree( + old_bytes: &[u8], + old_flags: &[bool], + from_height: usize, + to_height: usize, +) -> Option<(Vec, Vec)> { + let to_nodes = nodes_in_tree_of_height(to_height); + + let mut bytes = vec![0; to_nodes * HASHSIZE]; + let mut flags = vec![true; to_nodes]; + + for i in 0..=from_height { + let old_byte_slice = old_bytes.get(byte_range_at_height(i))?; + let old_flag_slice = old_flags.get(node_range_at_height(i))?; + + let offset = i + to_height - from_height; + let new_byte_slice = bytes.get_mut(byte_range_at_height(offset))?; + let new_flag_slice = flags.get_mut(node_range_at_height(offset))?; + + new_byte_slice + .get_mut(0..old_byte_slice.len())? + .copy_from_slice(old_byte_slice); + new_flag_slice + .get_mut(0..old_flag_slice.len())? + .copy_from_slice(old_flag_slice); + } + + Some((bytes, flags)) +} + +/// New vec is smaller than old vec. +pub fn shrink_merkle_tree( + from_bytes: &[u8], + from_flags: &[bool], + from_height: usize, + to_height: usize, +) -> Option<(Vec, Vec)> { + let to_nodes = nodes_in_tree_of_height(to_height); + + let mut bytes = vec![0; to_nodes * HASHSIZE]; + let mut flags = vec![true; to_nodes]; + + for i in 0..=to_height as usize { + let offset = i + from_height - to_height; + let from_byte_slice = from_bytes.get(byte_range_at_height(offset))?; + let from_flag_slice = from_flags.get(node_range_at_height(offset))?; + + let to_byte_slice = bytes.get_mut(byte_range_at_height(i))?; + let to_flag_slice = flags.get_mut(node_range_at_height(i))?; + + to_byte_slice.copy_from_slice(from_byte_slice.get(0..to_byte_slice.len())?); + to_flag_slice.copy_from_slice(from_flag_slice.get(0..to_flag_slice.len())?); + } + + Some((bytes, flags)) +} + +pub fn nodes_in_tree_of_height(h: usize) -> usize { + 2 * (1 << h) - 1 +} + +fn byte_range_at_height(h: usize) -> Range { + let node_range = node_range_at_height(h); + node_range.start * HASHSIZE..node_range.end * HASHSIZE +} + +fn node_range_at_height(h: usize) -> Range { + first_node_at_height(h)..last_node_at_height(h) + 1 +} + +fn first_node_at_height(h: usize) -> usize { + (1 << h) - 1 +} + +fn last_node_at_height(h: usize) -> usize { + (1 << (h + 1)) - 2 +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn can_grow_and_shrink_three_levels() { + let small: usize = 1; + let big: usize = 15; + + let original_bytes = vec![42; small * HASHSIZE]; + let original_flags = vec![false; small]; + + let (grown_bytes, grown_flags) = grow_merkle_tree( + &original_bytes, + &original_flags, + (small + 1).trailing_zeros() as usize - 1, + (big + 1).trailing_zeros() as usize - 1, + ) + .unwrap(); + + let mut expected_bytes = vec![]; + let mut expected_flags = vec![]; + // First level + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(true); + // Second level + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(true); + expected_flags.push(true); + // Third level + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + // Fourth level + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(false); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + + assert_eq!(expected_bytes, grown_bytes); + assert_eq!(expected_flags, grown_flags); + + let (shrunk_bytes, shrunk_flags) = shrink_merkle_tree( + &grown_bytes, + &grown_flags, + (big + 1).trailing_zeros() as usize - 1, + (small + 1).trailing_zeros() as usize - 1, + ) + .unwrap(); + + assert_eq!(original_bytes, shrunk_bytes); + assert_eq!(original_flags, shrunk_flags); + } + + #[test] + fn can_grow_and_shrink_one_level() { + let small: usize = 7; + let big: usize = 15; + + let original_bytes = vec![42; small * HASHSIZE]; + let original_flags = vec![false; small]; + + let (grown_bytes, grown_flags) = grow_merkle_tree( + &original_bytes, + &original_flags, + (small + 1).trailing_zeros() as usize - 1, + (big + 1).trailing_zeros() as usize - 1, + ) + .unwrap(); + + let mut expected_bytes = vec![]; + let mut expected_flags = vec![]; + // First level + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(true); + // Second level + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(false); + expected_flags.push(true); + // Third level + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(false); + expected_flags.push(false); + expected_flags.push(true); + expected_flags.push(true); + // Fourth level + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![42; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_bytes.append(&mut vec![0; 32]); + expected_flags.push(false); + expected_flags.push(false); + expected_flags.push(false); + expected_flags.push(false); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + expected_flags.push(true); + + assert_eq!(expected_bytes, grown_bytes); + assert_eq!(expected_flags, grown_flags); + + let (shrunk_bytes, shrunk_flags) = shrink_merkle_tree( + &grown_bytes, + &grown_flags, + (big + 1).trailing_zeros() as usize - 1, + (small + 1).trailing_zeros() as usize - 1, + ) + .unwrap(); + + assert_eq!(original_bytes, shrunk_bytes); + assert_eq!(original_flags, shrunk_flags); + } +} diff --git a/eth2/utils/cached_tree_hash/src/tree_hash_cache.rs b/eth2/utils/cached_tree_hash/src/tree_hash_cache.rs new file mode 100644 index 000000000..8f7b9de86 --- /dev/null +++ b/eth2/utils/cached_tree_hash/src/tree_hash_cache.rs @@ -0,0 +1,446 @@ +#![allow(clippy::range_plus_one)] // Minor readability lint requiring structural changes; not worth it. + +use super::*; +use crate::merkleize::{merkleize, pad_for_leaf_count}; +use int_to_bytes::int_to_bytes32; + +/// Provides cached tree hashing for some object implementing `CachedTreeHash`. +/// +/// Caching allows for doing minimal internal-node hashing when an object has only been partially +/// changed. +/// +/// See the crate root for an example. +#[derive(Debug, PartialEq, Clone)] +pub struct TreeHashCache { + /// Stores the binary-tree in 32-byte chunks. + pub bytes: Vec, + /// Maps to each chunk of `self.bytes`, indicating if the chunk is dirty. + pub chunk_modified: Vec, + /// Contains a schema for each variable-length item stored in the cache. + pub schemas: Vec, + + /// A counter used during updates. + pub chunk_index: usize, + /// A counter used during updates. + pub schema_index: usize, +} + +impl Default for TreeHashCache { + /// Create an empty cache. + /// + /// Note: an empty cache is effectively useless, an error will be raised if `self.update` is + /// called. + fn default() -> TreeHashCache { + TreeHashCache { + bytes: vec![], + chunk_modified: vec![], + schemas: vec![], + chunk_index: 0, + schema_index: 0, + } + } +} + +impl TreeHashCache { + /// Instantiates a new cache from `item` at a depth of `0`. + /// + /// The returned cache is fully-built and will return an accurate tree-hash root. + pub fn new(item: &T) -> Result + where + T: CachedTreeHash, + { + Self::new_at_depth(item, 0) + } + + /// Instantiates a new cache from `item` at the specified `depth`. + /// + /// The returned cache is fully-built and will return an accurate tree-hash root. + pub fn new_at_depth(item: &T, depth: usize) -> Result + where + T: CachedTreeHash, + { + item.new_tree_hash_cache(depth) + } + + /// Updates the cache with `item`. + /// + /// `item` _must_ be of the same type as the `item` used to build the cache, otherwise an error + /// may be returned. + /// + /// After calling `update`, the cache will return an accurate tree-hash root using + /// `self.tree_hash_root()`. + pub fn update(&mut self, item: &T) -> Result<(), Error> + where + T: CachedTreeHash, + { + if self.is_empty() { + Err(Error::CacheNotInitialized) + } else { + self.reset_modifications(); + + item.update_tree_hash_cache(self) + } + } + + /// Builds a new cache for `item`, given `subtrees` contains a `Self` for field/item of `item`. + /// + /// Each `subtree` in `subtree` will become a leaf-node of the merkle-tree of `item`. + pub fn from_subtrees(item: &T, subtrees: Vec, depth: usize) -> Result + where + T: CachedTreeHash, + { + let overlay = BTreeOverlay::new(item, 0, depth); + + // Note how many leaves were provided. If is not a power-of-two, we'll need to pad it out + // later. + let num_provided_leaf_nodes = subtrees.len(); + + // Allocate enough bytes to store the internal nodes and the leaves and subtrees, then fill + // all the to-be-built internal nodes with zeros and append the leaves and subtrees. + let internal_node_bytes = overlay.num_internal_nodes() * BYTES_PER_CHUNK; + let subtrees_bytes = subtrees.iter().fold(0, |acc, t| acc + t.bytes.len()); + let mut bytes = Vec::with_capacity(subtrees_bytes + internal_node_bytes); + bytes.resize(internal_node_bytes, 0); + + // Allocate enough bytes to store all the leaves. + let mut leaves = Vec::with_capacity(overlay.num_leaf_nodes() * HASHSIZE); + let mut schemas = Vec::with_capacity(subtrees.len()); + + if T::tree_hash_type() == TreeHashType::List { + schemas.push(overlay.into()); + } + + // Iterate through all of the leaves/subtrees, adding their root as a leaf node and then + // concatenating their merkle trees. + for t in subtrees { + leaves.append(&mut t.tree_hash_root()?.to_vec()); + + let (mut t_bytes, _bools, mut t_schemas) = t.into_components(); + bytes.append(&mut t_bytes); + schemas.append(&mut t_schemas); + } + + // Pad the leaves to an even power-of-two, using zeros. + pad_for_leaf_count(num_provided_leaf_nodes, &mut bytes); + + // Merkleize the leaves, then split the leaf nodes off them. Then, replace all-zeros + // internal nodes created earlier with the internal nodes generated by `merkleize`. + let mut merkleized = merkleize(leaves); + merkleized.split_off(internal_node_bytes); + bytes.splice(0..internal_node_bytes, merkleized); + + Ok(Self { + chunk_modified: vec![true; bytes.len() / BYTES_PER_CHUNK], + bytes, + schemas, + chunk_index: 0, + schema_index: 0, + }) + } + + /// Instantiate a new cache from the pre-built `bytes` where each `self.chunk_modified` will be + /// set to `intitial_modified_state`. + /// + /// Note: `bytes.len()` must be a multiple of 32 + pub fn from_bytes( + bytes: Vec, + initial_modified_state: bool, + schema: Option, + ) -> Result { + if bytes.len() % BYTES_PER_CHUNK > 0 { + return Err(Error::BytesAreNotEvenChunks(bytes.len())); + } + + let schemas = match schema { + Some(schema) => vec![schema], + None => vec![], + }; + + Ok(Self { + chunk_modified: vec![initial_modified_state; bytes.len() / BYTES_PER_CHUNK], + bytes, + schemas, + chunk_index: 0, + schema_index: 0, + }) + } + + /// Returns `true` if this cache is empty (i.e., it has never been built for some item). + /// + /// Note: an empty cache is effectively useless, an error will be raised if `self.update` is + /// called. + pub fn is_empty(&self) -> bool { + self.chunk_modified.is_empty() + } + + /// Return an overlay, built from the schema at `schema_index` with an offset of `chunk_index`. + pub fn get_overlay( + &self, + schema_index: usize, + chunk_index: usize, + ) -> Result { + Ok(self + .schemas + .get(schema_index) + .ok_or_else(|| Error::NoSchemaForIndex(schema_index))? + .clone() + .into_overlay(chunk_index)) + } + + /// Resets the per-update counters, allowing a new update to start. + /// + /// Note: this does _not_ delete the contents of the cache. + pub fn reset_modifications(&mut self) { + // Reset the per-hash counters. + self.chunk_index = 0; + self.schema_index = 0; + + for chunk_modified in &mut self.chunk_modified { + *chunk_modified = false; + } + } + + /// Replace the schema at `schema_index` with the schema derived from `new_overlay`. + /// + /// If the `new_overlay` schema has a different number of internal nodes to the schema at + /// `schema_index`, the cache will be updated to add/remove these new internal nodes. + pub fn replace_overlay( + &mut self, + schema_index: usize, + // TODO: remove chunk index (if possible) + chunk_index: usize, + new_overlay: BTreeOverlay, + ) -> Result { + let old_overlay = self.get_overlay(schema_index, chunk_index)?; + // If the merkle tree required to represent the new list is of a different size to the one + // required for the previous list, then update the internal nodes. + // + // Leaf nodes are not touched, they should be updated externally to this function. + // + // This grows/shrinks the bytes to accommodate the new tree, preserving as much of the tree + // as possible. + if new_overlay.num_internal_nodes() != old_overlay.num_internal_nodes() { + // Get slices of the existing tree from the cache. + let (old_bytes, old_flags) = self + .slices(old_overlay.internal_chunk_range()) + .ok_or_else(|| Error::UnableToObtainSlices)?; + + let (new_bytes, new_flags) = if new_overlay.num_internal_nodes() == 0 { + // The new tree has zero internal nodes, simply return empty lists. + (vec![], vec![]) + } else if old_overlay.num_internal_nodes() == 0 { + // The old tree has zero nodes and the new tree has some nodes. Create new nodes to + // suit. + let nodes = resize::nodes_in_tree_of_height(new_overlay.height() - 1); + + (vec![0; nodes * HASHSIZE], vec![true; nodes]) + } else if new_overlay.num_internal_nodes() > old_overlay.num_internal_nodes() { + // The new tree is bigger than the old tree. + // + // Grow the internal nodes, preserving any existing nodes. + resize::grow_merkle_tree( + old_bytes, + old_flags, + old_overlay.height() - 1, + new_overlay.height() - 1, + ) + .ok_or_else(|| Error::UnableToGrowMerkleTree)? + } else { + // The new tree is smaller than the old tree. + // + // Shrink the internal nodes, preserving any existing nodes. + resize::shrink_merkle_tree( + old_bytes, + old_flags, + old_overlay.height() - 1, + new_overlay.height() - 1, + ) + .ok_or_else(|| Error::UnableToShrinkMerkleTree)? + }; + + // Splice the resized created elements over the existing elements, effectively updating + // the number of stored internal nodes for this tree. + self.splice(old_overlay.internal_chunk_range(), new_bytes, new_flags); + } + + let old_schema = std::mem::replace(&mut self.schemas[schema_index], new_overlay.into()); + + Ok(old_schema.into_overlay(chunk_index)) + } + + /// Remove all of the child schemas following `schema_index`. + /// + /// Schema `a` is a child of schema `b` if `a.depth < b.depth`. + pub fn remove_proceeding_child_schemas(&mut self, schema_index: usize, depth: usize) { + let end = self + .schemas + .iter() + .skip(schema_index) + .position(|o| o.depth <= depth) + .and_then(|i| Some(i + schema_index)) + .unwrap_or_else(|| self.schemas.len()); + + self.schemas.splice(schema_index..end, vec![]); + } + + /// Iterate through the internal nodes chunks of `overlay`, updating the chunk with the + /// merkle-root of it's children if either of those children are dirty. + pub fn update_internal_nodes(&mut self, overlay: &BTreeOverlay) -> Result<(), Error> { + for (parent, children) in overlay.internal_parents_and_children().into_iter().rev() { + if self.either_modified(children)? { + self.modify_chunk(parent, &self.hash_children(children)?)?; + } + } + + Ok(()) + } + + /// Returns to the tree-hash root of the cache. + pub fn tree_hash_root(&self) -> Result<&[u8], Error> { + if self.is_empty() { + Err(Error::CacheNotInitialized) + } else { + self.bytes + .get(0..HASHSIZE) + .ok_or_else(|| Error::NoBytesForRoot) + } + } + + /// Splices the given `bytes` over `self.bytes` and `bools` over `self.chunk_modified` at the + /// specified `chunk_range`. + pub fn splice(&mut self, chunk_range: Range, bytes: Vec, bools: Vec) { + // Update the `chunk_modified` vec, marking all spliced-in nodes as changed. + self.chunk_modified.splice(chunk_range.clone(), bools); + self.bytes + .splice(node_range_to_byte_range(&chunk_range), bytes); + } + + /// If the bytes at `chunk` are not the same as `to`, `self.bytes` is updated and + /// `self.chunk_modified` is set to `true`. + pub fn maybe_update_chunk(&mut self, chunk: usize, to: &[u8]) -> Result<(), Error> { + let start = chunk * BYTES_PER_CHUNK; + let end = start + BYTES_PER_CHUNK; + + if !self.chunk_equals(chunk, to)? { + self.bytes + .get_mut(start..end) + .ok_or_else(|| Error::NoModifiedFieldForChunk(chunk))? + .copy_from_slice(to); + self.chunk_modified[chunk] = true; + } + + Ok(()) + } + + /// Returns the slices of `self.bytes` and `self.chunk_modified` at the given `chunk_range`. + fn slices(&self, chunk_range: Range) -> Option<(&[u8], &[bool])> { + Some(( + self.bytes.get(node_range_to_byte_range(&chunk_range))?, + self.chunk_modified.get(chunk_range)?, + )) + } + + /// Updates `self.bytes` at `chunk` and sets `self.chunk_modified` for the `chunk` to `true`. + pub fn modify_chunk(&mut self, chunk: usize, to: &[u8]) -> Result<(), Error> { + let start = chunk * BYTES_PER_CHUNK; + let end = start + BYTES_PER_CHUNK; + + self.bytes + .get_mut(start..end) + .ok_or_else(|| Error::NoBytesForChunk(chunk))? + .copy_from_slice(to); + + self.chunk_modified[chunk] = true; + + Ok(()) + } + + /// Returns the bytes at `chunk`. + fn get_chunk(&self, chunk: usize) -> Result<&[u8], Error> { + let start = chunk * BYTES_PER_CHUNK; + let end = start + BYTES_PER_CHUNK; + + Ok(self + .bytes + .get(start..end) + .ok_or_else(|| Error::NoModifiedFieldForChunk(chunk))?) + } + + /// Returns `true` if the bytes at `chunk` are equal to `other`. + fn chunk_equals(&mut self, chunk: usize, other: &[u8]) -> Result { + Ok(self.get_chunk(chunk)? == other) + } + + /// Returns `true` if `chunk` is dirty. + pub fn changed(&self, chunk: usize) -> Result { + self.chunk_modified + .get(chunk) + .cloned() + .ok_or_else(|| Error::NoModifiedFieldForChunk(chunk)) + } + + /// Returns `true` if either of the `children` chunks is dirty. + fn either_modified(&self, children: (usize, usize)) -> Result { + Ok(self.changed(children.0)? | self.changed(children.1)?) + } + + /// Returns the hash of the concatenation of the given `children`. + pub fn hash_children(&self, children: (usize, usize)) -> Result, Error> { + let mut child_bytes = Vec::with_capacity(BYTES_PER_CHUNK * 2); + child_bytes.append(&mut self.get_chunk(children.0)?.to_vec()); + child_bytes.append(&mut self.get_chunk(children.1)?.to_vec()); + + Ok(hash(&child_bytes)) + } + + /// Adds a chunk before and after the given `chunk` range and calls `self.mix_in_length()`. + pub fn add_length_nodes( + &mut self, + chunk_range: Range, + length: usize, + ) -> Result<(), Error> { + self.chunk_modified[chunk_range.start] = true; + + let byte_range = node_range_to_byte_range(&chunk_range); + + // Add the last node. + self.bytes + .splice(byte_range.end..byte_range.end, vec![0; HASHSIZE]); + self.chunk_modified + .splice(chunk_range.end..chunk_range.end, vec![false]); + + // Add the first node. + self.bytes + .splice(byte_range.start..byte_range.start, vec![0; HASHSIZE]); + self.chunk_modified + .splice(chunk_range.start..chunk_range.start, vec![false]); + + self.mix_in_length(chunk_range.start + 1..chunk_range.end + 1, length)?; + + Ok(()) + } + + /// Sets `chunk_range.end + 1` equal to the little-endian serialization of `length`. Sets + /// `chunk_range.start - 1` equal to `self.hash_children(chunk_range.start, chunk_range.end + 1)`. + pub fn mix_in_length(&mut self, chunk_range: Range, length: usize) -> Result<(), Error> { + // Update the length chunk. + self.maybe_update_chunk(chunk_range.end, &int_to_bytes32(length as u64))?; + + // Update the mixed-in root if the main root or the length have changed. + let children = (chunk_range.start, chunk_range.end); + if self.either_modified(children)? { + self.modify_chunk(chunk_range.start - 1, &self.hash_children(children)?)?; + } + + Ok(()) + } + + /// Returns `(self.bytes, self.chunk_modified, self.schemas)`. + pub fn into_components(self) -> (Vec, Vec, Vec) { + (self.bytes, self.chunk_modified, self.schemas) + } +} + +fn node_range_to_byte_range(node_range: &Range) -> Range { + node_range.start * HASHSIZE..node_range.end * HASHSIZE +} diff --git a/eth2/utils/cached_tree_hash/tests/tests.rs b/eth2/utils/cached_tree_hash/tests/tests.rs new file mode 100644 index 000000000..3e2598e2b --- /dev/null +++ b/eth2/utils/cached_tree_hash/tests/tests.rs @@ -0,0 +1,677 @@ +use cached_tree_hash::{merkleize::merkleize, *}; +use ethereum_types::H256 as Hash256; +use int_to_bytes::int_to_bytes32; +use tree_hash_derive::{CachedTreeHash, TreeHash}; + +#[test] +fn modifications() { + let n = 2048; + + let vec: Vec = (0..n).map(|_| Hash256::random()).collect(); + + let mut cache = TreeHashCache::new(&vec).unwrap(); + cache.update(&vec).unwrap(); + + let modifications = cache.chunk_modified.iter().filter(|b| **b).count(); + + assert_eq!(modifications, 0); + + let mut modified_vec = vec.clone(); + modified_vec[n - 1] = Hash256::random(); + + cache.update(&modified_vec).unwrap(); + + let modifications = cache.chunk_modified.iter().filter(|b| **b).count(); + + assert_eq!(modifications, n.trailing_zeros() as usize + 2); +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct NestedStruct { + pub a: u64, + pub b: Inner, +} + +fn test_routine(original: T, modified: Vec) +where + T: CachedTreeHash + std::fmt::Debug, +{ + let mut cache = TreeHashCache::new(&original).unwrap(); + + let standard_root = original.tree_hash_root(); + let cached_root = cache.tree_hash_root().unwrap(); + assert_eq!(standard_root, cached_root, "Initial cache build failed."); + + for (i, modified) in modified.iter().enumerate() { + println!("-- Start of modification {} --", i); + + // Update the existing hasher. + cache + .update(modified) + .expect(&format!("Modification {}", i)); + + // Create a new hasher from the "modified" struct. + let modified_cache = TreeHashCache::new(modified).unwrap(); + + assert_eq!( + cache.chunk_modified.len(), + modified_cache.chunk_modified.len(), + "Number of chunks is different" + ); + + assert_eq!( + cache.bytes.len(), + modified_cache.bytes.len(), + "Number of bytes is different" + ); + + assert_eq!(cache.bytes, modified_cache.bytes, "Bytes are different"); + + assert_eq!( + cache.schemas.len(), + modified_cache.schemas.len(), + "Number of schemas is different" + ); + + assert_eq!( + cache.schemas, modified_cache.schemas, + "Schemas are different" + ); + + // Test the root generated by the updated hasher matches a non-cached tree hash root. + let standard_root = modified.tree_hash_root(); + let cached_root = cache + .tree_hash_root() + .expect(&format!("Modification {}", i)); + assert_eq!( + standard_root, cached_root, + "Modification {} failed. \n Cache: {:?}", + i, cache + ); + } +} + +#[test] +fn test_nested_struct() { + let original = NestedStruct { + a: 42, + b: Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }, + }; + let modified = vec![NestedStruct { + a: 99, + ..original.clone() + }]; + + test_routine(original, modified); +} + +#[test] +fn test_inner() { + let original = Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }; + + let modified = vec![Inner { + a: 99, + ..original.clone() + }]; + + test_routine(original, modified); +} + +#[test] +fn test_vec_of_hash256() { + let n = 16; + + let original: Vec = (0..n).map(|_| Hash256::random()).collect(); + + let modified: Vec> = vec![ + original[..].to_vec(), + original[0..n / 2].to_vec(), + vec![], + original[0..1].to_vec(), + original[0..3].to_vec(), + original[0..n - 12].to_vec(), + ]; + + test_routine(original, modified); +} + +#[test] +fn test_vec_of_u64() { + let original: Vec = vec![1, 2, 3, 4, 5]; + + let modified: Vec> = vec![ + vec![1, 2, 3, 4, 42], + vec![1, 2, 3, 4], + vec![], + vec![42; 2_usize.pow(4)], + vec![], + vec![], + vec![1, 2, 3, 4, 42], + vec![1, 2, 3], + vec![1], + ]; + + test_routine(original, modified); +} + +#[test] +fn test_nested_list_of_u64() { + let original: Vec> = vec![vec![42]]; + + let modified = vec![ + vec![vec![1]], + vec![vec![1], vec![2]], + vec![vec![1], vec![3], vec![4]], + vec![], + vec![vec![1], vec![3], vec![4]], + vec![], + vec![vec![1, 2], vec![3], vec![4, 5, 6, 7, 8]], + vec![], + vec![vec![1], vec![2], vec![3]], + vec![vec![1, 2, 3, 4, 5, 6], vec![1, 2, 3, 4, 5, 6, 7]], + vec![vec![], vec![], vec![]], + vec![vec![0, 0, 0], vec![0], vec![0]], + ]; + + test_routine(original, modified); +} + +#[test] +fn test_shrinking_vec_of_vec() { + let original: Vec> = vec![vec![1], vec![2], vec![3], vec![4], vec![5]]; + let modified: Vec> = original[0..3].to_vec(); + + let new_cache = TreeHashCache::new(&modified).unwrap(); + + let mut modified_cache = TreeHashCache::new(&original).unwrap(); + modified_cache.update(&modified).unwrap(); + + assert_eq!( + new_cache.schemas.len(), + modified_cache.schemas.len(), + "Schema count is different" + ); + + assert_eq!( + new_cache.chunk_modified.len(), + modified_cache.chunk_modified.len(), + "Chunk count is different" + ); +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct StructWithVec { + pub a: u64, + pub b: Inner, + pub c: Vec, +} + +#[test] +fn test_struct_with_vec() { + let original = StructWithVec { + a: 42, + b: Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }, + c: vec![1, 2, 3, 4, 5], + }; + + let modified = vec![ + StructWithVec { + a: 99, + ..original.clone() + }, + StructWithVec { + a: 100, + ..original.clone() + }, + StructWithVec { + c: vec![1, 2, 3, 4, 5], + ..original.clone() + }, + StructWithVec { + c: vec![1, 3, 4, 5, 6], + ..original.clone() + }, + StructWithVec { + c: vec![1, 3, 4, 5, 6, 7, 8, 9], + ..original.clone() + }, + StructWithVec { + c: vec![1, 3, 4, 5], + ..original.clone() + }, + StructWithVec { + b: Inner { + a: u64::max_value(), + b: u64::max_value(), + c: u64::max_value(), + d: u64::max_value(), + }, + c: vec![], + ..original.clone() + }, + StructWithVec { + b: Inner { + a: 0, + b: 1, + c: 2, + d: 3, + }, + ..original.clone() + }, + ]; + + test_routine(original, modified); +} + +#[test] +fn test_vec_of_struct_with_vec() { + let a = StructWithVec { + a: 42, + b: Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }, + c: vec![1, 2, 3, 4, 5], + }; + let b = StructWithVec { + c: vec![], + ..a.clone() + }; + let c = StructWithVec { + b: Inner { + a: 99, + b: 100, + c: 101, + d: 102, + }, + ..a.clone() + }; + let d = StructWithVec { a: 0, ..a.clone() }; + + let original: Vec = vec![a.clone(), c.clone()]; + + let modified = vec![ + vec![a.clone(), c.clone()], + vec![], + vec![a.clone(), b.clone(), c.clone(), d.clone()], + vec![b.clone(), a.clone(), c.clone(), d.clone()], + vec![], + vec![a.clone()], + vec![], + vec![a.clone(), b.clone(), c.clone(), d.clone()], + ]; + + test_routine(original, modified); +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct StructWithVecOfStructs { + pub a: u64, + pub b: Inner, + pub c: Vec, +} + +fn get_inners() -> Vec { + vec![ + Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }, + Inner { + a: 99, + b: 100, + c: 101, + d: 102, + }, + Inner { + a: 255, + b: 256, + c: 257, + d: 0, + }, + Inner { + a: 1000, + b: 2000, + c: 3000, + d: 0, + }, + Inner { + a: 0, + b: 0, + c: 0, + d: 0, + }, + ] +} + +fn get_struct_with_vec_of_structs() -> Vec { + let inner_a = Inner { + a: 12, + b: 13, + c: 14, + d: 15, + }; + + let inner_b = Inner { + a: 99, + b: 100, + c: 101, + d: 102, + }; + + let inner_c = Inner { + a: 255, + b: 256, + c: 257, + d: 0, + }; + + let a = StructWithVecOfStructs { + a: 42, + b: inner_a.clone(), + c: vec![inner_a.clone(), inner_b.clone(), inner_c.clone()], + }; + + let b = StructWithVecOfStructs { + c: vec![], + ..a.clone() + }; + + let c = StructWithVecOfStructs { + a: 800, + ..a.clone() + }; + + let d = StructWithVecOfStructs { + b: inner_c.clone(), + ..a.clone() + }; + + let e = StructWithVecOfStructs { + c: vec![inner_a.clone(), inner_b.clone()], + ..a.clone() + }; + + let f = StructWithVecOfStructs { + c: vec![inner_a.clone()], + ..a.clone() + }; + + vec![a, b, c, d, e, f] +} + +#[test] +fn test_struct_with_vec_of_structs() { + let variants = get_struct_with_vec_of_structs(); + + test_routine(variants[0].clone(), variants.clone()); + test_routine(variants[1].clone(), variants.clone()); + test_routine(variants[2].clone(), variants.clone()); + test_routine(variants[3].clone(), variants.clone()); + test_routine(variants[4].clone(), variants.clone()); + test_routine(variants[5].clone(), variants.clone()); +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct StructWithVecOfStructWithVecOfStructs { + pub a: Vec, + pub b: u64, +} + +#[test] +fn test_struct_with_vec_of_struct_with_vec_of_structs() { + let structs = get_struct_with_vec_of_structs(); + + let variants = vec![ + StructWithVecOfStructWithVecOfStructs { + a: structs[..].to_vec(), + b: 99, + }, + StructWithVecOfStructWithVecOfStructs { a: vec![], b: 99 }, + StructWithVecOfStructWithVecOfStructs { + a: structs[0..2].to_vec(), + b: 99, + }, + StructWithVecOfStructWithVecOfStructs { + a: structs[0..2].to_vec(), + b: 100, + }, + StructWithVecOfStructWithVecOfStructs { + a: structs[0..1].to_vec(), + b: 100, + }, + StructWithVecOfStructWithVecOfStructs { + a: structs[0..4].to_vec(), + b: 100, + }, + StructWithVecOfStructWithVecOfStructs { + a: structs[0..5].to_vec(), + b: 8, + }, + ]; + + for v in &variants { + test_routine(v.clone(), variants.clone()); + } +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct StructWithTwoVecs { + pub a: Vec, + pub b: Vec, +} + +fn get_struct_with_two_vecs() -> Vec { + let inners = get_inners(); + + vec![ + StructWithTwoVecs { + a: inners[..].to_vec(), + b: inners[..].to_vec(), + }, + StructWithTwoVecs { + a: inners[0..1].to_vec(), + b: inners[..].to_vec(), + }, + StructWithTwoVecs { + a: inners[0..1].to_vec(), + b: inners[0..2].to_vec(), + }, + StructWithTwoVecs { + a: inners[0..4].to_vec(), + b: inners[0..2].to_vec(), + }, + StructWithTwoVecs { + a: vec![], + b: inners[..].to_vec(), + }, + StructWithTwoVecs { + a: inners[..].to_vec(), + b: vec![], + }, + StructWithTwoVecs { + a: inners[0..3].to_vec(), + b: inners[0..1].to_vec(), + }, + ] +} + +#[test] +fn test_struct_with_two_vecs() { + let variants = get_struct_with_two_vecs(); + + for v in &variants { + test_routine(v.clone(), variants.clone()); + } +} + +#[test] +fn test_vec_of_struct_with_two_vecs() { + let structs = get_struct_with_two_vecs(); + + let variants = vec![ + structs[0..].to_vec(), + structs[0..2].to_vec(), + structs[2..3].to_vec(), + vec![], + structs[2..4].to_vec(), + ]; + + test_routine(variants[0].clone(), vec![variants[2].clone()]); + + for v in &variants { + test_routine(v.clone(), variants.clone()); + } +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct U64AndTwoStructs { + pub a: u64, + pub b: Inner, + pub c: Inner, +} + +#[test] +fn test_u64_and_two_structs() { + let inners = get_inners(); + + let variants = vec![ + U64AndTwoStructs { + a: 99, + b: inners[0].clone(), + c: inners[1].clone(), + }, + U64AndTwoStructs { + a: 10, + b: inners[2].clone(), + c: inners[3].clone(), + }, + U64AndTwoStructs { + a: 0, + b: inners[1].clone(), + c: inners[1].clone(), + }, + U64AndTwoStructs { + a: 0, + b: inners[1].clone(), + c: inners[1].clone(), + }, + ]; + + for v in &variants { + test_routine(v.clone(), variants.clone()); + } +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct Inner { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, +} + +fn generic_test(index: usize) { + let inner = Inner { + a: 1, + b: 2, + c: 3, + d: 4, + }; + + let mut cache = TreeHashCache::new(&inner).unwrap(); + + let changed_inner = match index { + 0 => Inner { + a: 42, + ..inner.clone() + }, + 1 => Inner { + b: 42, + ..inner.clone() + }, + 2 => Inner { + c: 42, + ..inner.clone() + }, + 3 => Inner { + d: 42, + ..inner.clone() + }, + _ => panic!("bad index"), + }; + + changed_inner.update_tree_hash_cache(&mut cache).unwrap(); + + let data1 = int_to_bytes32(1); + let data2 = int_to_bytes32(2); + let data3 = int_to_bytes32(3); + let data4 = int_to_bytes32(4); + + let mut data = vec![data1, data2, data3, data4]; + + data[index] = int_to_bytes32(42); + + let expected = merkleize(join(data)); + + let (cache_bytes, _, _) = cache.into_components(); + + assert_eq!(expected, cache_bytes); +} + +#[test] +fn cached_hash_on_inner() { + generic_test(0); + generic_test(1); + generic_test(2); + generic_test(3); +} + +#[test] +fn inner_builds() { + let data1 = int_to_bytes32(1); + let data2 = int_to_bytes32(2); + let data3 = int_to_bytes32(3); + let data4 = int_to_bytes32(4); + + let data = join(vec![data1, data2, data3, data4]); + let expected = merkleize(data); + + let inner = Inner { + a: 1, + b: 2, + c: 3, + d: 4, + }; + + let (cache_bytes, _, _) = TreeHashCache::new(&inner).unwrap().into_components(); + + assert_eq!(expected, cache_bytes); +} + +fn join(many: Vec>) -> Vec { + let mut all = vec![]; + for one in many { + all.extend_from_slice(&mut one.clone()) + } + all +} diff --git a/eth2/utils/fixed_len_vec/Cargo.toml b/eth2/utils/fixed_len_vec/Cargo.toml new file mode 100644 index 000000000..ddfc33103 --- /dev/null +++ b/eth2/utils/fixed_len_vec/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fixed_len_vec" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dependencies] +cached_tree_hash = { path = "../cached_tree_hash" } +tree_hash = { path = "../tree_hash" } +serde = "1.0" +serde_derive = "1.0" +ssz = { path = "../ssz" } +typenum = "1.10" diff --git a/eth2/utils/fixed_len_vec/src/impls.rs b/eth2/utils/fixed_len_vec/src/impls.rs new file mode 100644 index 000000000..e1c54c1f7 --- /dev/null +++ b/eth2/utils/fixed_len_vec/src/impls.rs @@ -0,0 +1,140 @@ +use super::*; + +impl tree_hash::TreeHash for FixedLenVec +where + T: tree_hash::TreeHash, +{ + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::Vector + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + tree_hash::impls::vec_tree_hash_root(&self.vec) + } +} + +impl cached_tree_hash::CachedTreeHash for FixedLenVec +where + T: cached_tree_hash::CachedTreeHash + tree_hash::TreeHash, +{ + fn new_tree_hash_cache( + &self, + depth: usize, + ) -> Result { + let (cache, _overlay) = cached_tree_hash::vec::new_tree_hash_cache(&self.vec, depth)?; + + Ok(cache) + } + + fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema { + cached_tree_hash::vec::produce_schema(&self.vec, depth) + } + + fn update_tree_hash_cache( + &self, + cache: &mut cached_tree_hash::TreeHashCache, + ) -> Result<(), cached_tree_hash::Error> { + cached_tree_hash::vec::update_tree_hash_cache(&self.vec, cache)?; + + Ok(()) + } +} + +impl ssz::Encode for FixedLenVec +where + T: ssz::Encode, +{ + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + if ::is_ssz_fixed_len() { + T::ssz_fixed_len() * N::to_usize() + } else { + ssz::BYTES_PER_LENGTH_OFFSET + } + } + + fn ssz_append(&self, buf: &mut Vec) { + if T::is_ssz_fixed_len() { + buf.reserve(T::ssz_fixed_len() * self.len()); + + for item in &self.vec { + item.ssz_append(buf); + } + } else { + let mut encoder = ssz::SszEncoder::list(buf, self.len() * ssz::BYTES_PER_LENGTH_OFFSET); + + for item in &self.vec { + encoder.append(item); + } + + encoder.finalize(); + } + } +} + +impl ssz::Decode for FixedLenVec +where + T: ssz::Decode + Default, +{ + fn is_ssz_fixed_len() -> bool { + T::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + if ::is_ssz_fixed_len() { + T::ssz_fixed_len() * N::to_usize() + } else { + ssz::BYTES_PER_LENGTH_OFFSET + } + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + if bytes.len() == 0 { + Ok(FixedLenVec::from(vec![])) + } else if T::is_ssz_fixed_len() { + bytes + .chunks(T::ssz_fixed_len()) + .map(|chunk| T::from_ssz_bytes(chunk)) + .collect::, _>>() + .and_then(|vec| Ok(vec.into())) + } else { + ssz::decode_list_of_variable_length_items(bytes).and_then(|vec| Ok(vec.into())) + } + } +} + +#[cfg(test)] +mod ssz_tests { + use super::*; + use ssz::*; + use typenum::*; + + #[test] + fn encode() { + let vec: FixedLenVec = vec![0; 2].into(); + assert_eq!(vec.as_ssz_bytes(), vec![0, 0, 0, 0]); + assert_eq!( as Encode>::ssz_fixed_len(), 4); + } + + fn round_trip(item: T) { + let encoded = &item.as_ssz_bytes(); + assert_eq!(T::from_ssz_bytes(&encoded), Ok(item)); + } + + #[test] + fn u16_len_8() { + round_trip::>(vec![42; 8].into()); + round_trip::>(vec![0; 8].into()); + } +} diff --git a/eth2/utils/fixed_len_vec/src/lib.rs b/eth2/utils/fixed_len_vec/src/lib.rs new file mode 100644 index 000000000..2976ee4e4 --- /dev/null +++ b/eth2/utils/fixed_len_vec/src/lib.rs @@ -0,0 +1,115 @@ +use serde_derive::{Deserialize, Serialize}; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; +use std::slice::SliceIndex; +use typenum::Unsigned; + +pub use typenum; + +mod impls; + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct FixedLenVec { + vec: Vec, + _phantom: PhantomData, +} + +impl FixedLenVec { + pub fn len(&self) -> usize { + self.vec.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn capacity() -> usize { + N::to_usize() + } +} + +impl From> for FixedLenVec { + fn from(mut vec: Vec) -> Self { + vec.resize_with(Self::capacity(), Default::default); + + Self { + vec, + _phantom: PhantomData, + } + } +} + +impl Into> for FixedLenVec { + fn into(self) -> Vec { + self.vec + } +} + +impl Default for FixedLenVec { + fn default() -> Self { + Self { + vec: Vec::default(), + _phantom: PhantomData, + } + } +} + +impl> Index for FixedLenVec { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(&self.vec, index) + } +} + +impl> IndexMut for FixedLenVec { + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut self.vec, index) + } +} + +#[cfg(test)] +mod test { + use super::*; + use typenum::*; + + #[test] + fn indexing() { + let vec = vec![1, 2]; + + let mut fixed: FixedLenVec = vec.clone().into(); + + assert_eq!(fixed[0], 1); + assert_eq!(&fixed[0..1], &vec[0..1]); + assert_eq!((&fixed[..]).len(), 8192); + + fixed[1] = 3; + assert_eq!(fixed[1], 3); + } + + #[test] + fn length() { + let vec = vec![42; 5]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[..], &vec[0..4]); + + let vec = vec![42; 3]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[0..3], &vec[..]); + assert_eq!(&fixed[..], &vec![42, 42, 42, 0][..]); + + let vec = vec![]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[..], &vec![0, 0, 0, 0][..]); + } +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/eth2/utils/hashing/src/lib.rs b/eth2/utils/hashing/src/lib.rs index b2bd5a279..d1d2c28d9 100644 --- a/eth2/utils/hashing/src/lib.rs +++ b/eth2/utils/hashing/src/lib.rs @@ -8,6 +8,36 @@ pub fn hash(input: &[u8]) -> Vec { result } +/// Get merkle root of some hashed values - the input leaf nodes is expected to already be hashed +/// Outputs a `Vec` byte array of the merkle root given a set of leaf node values. +pub fn merkle_root(values: &[Vec]) -> Option> { + let values_len = values.len(); + + // check size of vector > 0 and ^ 2 + if values.is_empty() || !values_len.is_power_of_two() { + return None; + } + + // vector to store hashes + // filled with 0 as placeholders + let mut o: Vec> = vec![vec![0]; values_len]; + + // append values to the end + o.append(&mut values.to_vec()); + + // traverse backwards as values are at the end + // then fill placeholders with a hash of two leaf nodes + for i in (0..values_len).rev() { + let mut current_value: Vec = o[i * 2].clone(); + current_value.append(&mut o[i * 2 + 1].clone()); + + o[i] = hash(¤t_value[..]); + } + + // the root hash will be at index 1 + Some(o[1].clone()) +} + #[cfg(test)] mod tests { use super::*; @@ -25,4 +55,51 @@ mod tests { ]; assert_eq!(expected, output.as_slice()); } + + #[test] + fn test_merkle_root() { + // hash the leaf nodes + let mut input = vec![ + hash("a".as_bytes()), + hash("b".as_bytes()), + hash("c".as_bytes()), + hash("d".as_bytes()), + ]; + + // generate a merkle tree and return the root + let output = merkle_root(&input[..]); + + // create merkle root manually + let mut leaf_1_2: Vec = input[0].clone(); // a + leaf_1_2.append(&mut input[1].clone()); // b + + let mut leaf_3_4: Vec = input[2].clone(); // c + leaf_3_4.append(&mut input[3].clone()); // d + + let node_1 = hash(&leaf_1_2[..]); + let node_2 = hash(&leaf_3_4[..]); + + let mut root: Vec = node_1.clone(); // ab + root.append(&mut node_2.clone()); // cd + + let expected = hash(&root[..]); + + assert_eq!(&expected[..], output.unwrap().as_slice()); + } + #[test] + fn test_empty_input_merkle_root() { + let input = vec![]; + let output = merkle_root(&input[..]); + assert_eq!(None, output); + } + #[test] + fn test_odd_leaf_merkle_root() { + let input = vec![ + hash("a".as_bytes()), + hash("b".as_bytes()), + hash("a".as_bytes()), + ]; + let output = merkle_root(&input[..]); + assert_eq!(None, output); + } } diff --git a/eth2/utils/ssz/Cargo.toml b/eth2/utils/ssz/Cargo.toml index fa042a8ac..0423b1a8b 100644 --- a/eth2/utils/ssz/Cargo.toml +++ b/eth2/utils/ssz/Cargo.toml @@ -4,9 +4,18 @@ version = "0.1.0" authors = ["Paul Hauner "] edition = "2018" +[[bench]] +name = "benches" +harness = false + +[dev-dependencies] +criterion = "0.2" +ssz_derive = { path = "../ssz_derive" } + [dependencies] bytes = "0.4.9" ethereum-types = "0.5" hashing = { path = "../hashing" } +int_to_bytes = { path = "../int_to_bytes" } hex = "0.3" yaml-rust = "0.4" diff --git a/eth2/utils/ssz/README.md b/eth2/utils/ssz/README.md index 30d8ded72..0a9bbff25 100644 --- a/eth2/utils/ssz/README.md +++ b/eth2/utils/ssz/README.md @@ -38,8 +38,8 @@ spec is decided.*\ + [bytes v0.4.9](#bytes-v049) + [ethereum-types](#ethereum-types) * [Interface](#interface) - + [Encodable](#encodable) - + [Decodable](#decodable) + + [Encode](#encodable) + + [Decode](#decodable) + [SszStream](#sszstream) - [new()](#new) - [append(&mut self, value: &E) -> &mut Self](#appendmut-self-value-e---mut-self) @@ -299,24 +299,24 @@ Github: [ https://github.com/paritytech/primitives ](https://github.com/parityte ## Interface -### Encodable +### Encode -A type is **Encodable** if it has a valid ``ssz_append`` function. This is +A type is **Encode** if it has a valid ``ssz_append`` function. This is used to ensure that the object/type can be serialized. ```rust -pub trait Encodable { +pub trait Encode { fn ssz_append(&self, s: &mut SszStream); } ``` -### Decodable +### Decode -A type is **Decodable** if it has a valid ``ssz_decode`` function. This is +A type is **Decode** if it has a valid ``ssz_decode`` function. This is used to ensure the object is deserializable. ```rust -pub trait Decodable: Sized { +pub trait Decode: Sized { fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError>; } ``` @@ -342,7 +342,7 @@ Appends a value that can be encoded into the stream. | Parameter | Description | |:---------:|:-----------------------------------------| -| ``value`` | Encodable value to append to the stream. | +| ``value`` | Encode value to append to the stream. | **Example** @@ -371,7 +371,7 @@ Appends some vector (list) of encodable values to the stream. | Parameter | Description | |:---------:|:----------------------------------------------| -| ``vec`` | Vector of Encodable objects to be serialized. | +| ``vec`` | Vector of Encode objects to be serialized. | **Example** diff --git a/eth2/utils/ssz/benches/benches.rs b/eth2/utils/ssz/benches/benches.rs new file mode 100644 index 000000000..4604b0cd8 --- /dev/null +++ b/eth2/utils/ssz/benches/benches.rs @@ -0,0 +1,80 @@ +#[macro_use] +extern crate criterion; + +use criterion::black_box; +use criterion::{Benchmark, Criterion}; +use ssz::{Decode, Encode}; +use ssz_derive::{Decode, Encode}; + +#[derive(Clone, Copy, Encode, Decode)] +pub struct FixedLen { + a: u64, + b: u64, + c: u64, + d: u64, +} + +fn criterion_benchmark(c: &mut Criterion) { + let n = 8196; + + let vec: Vec = vec![4242; 8196]; + c.bench( + &format!("vec_of_{}_u64", n), + Benchmark::new("as_ssz_bytes", move |b| { + b.iter_with_setup(|| vec.clone(), |vec| black_box(vec.as_ssz_bytes())) + }) + .sample_size(100), + ); + + let vec: Vec = vec![4242; 8196]; + let bytes = vec.as_ssz_bytes(); + c.bench( + &format!("vec_of_{}_u64", n), + Benchmark::new("from_ssz_bytes", move |b| { + b.iter_with_setup( + || bytes.clone(), + |bytes| { + let vec: Vec = Vec::from_ssz_bytes(&bytes).unwrap(); + black_box(vec) + }, + ) + }) + .sample_size(100), + ); + + let fixed_len = FixedLen { + a: 42, + b: 42, + c: 42, + d: 42, + }; + let fixed_len_vec: Vec = vec![fixed_len; 8196]; + + let vec = fixed_len_vec.clone(); + c.bench( + &format!("vec_of_{}_struct", n), + Benchmark::new("as_ssz_bytes", move |b| { + b.iter_with_setup(|| vec.clone(), |vec| black_box(vec.as_ssz_bytes())) + }) + .sample_size(100), + ); + + let vec = fixed_len_vec.clone(); + let bytes = vec.as_ssz_bytes(); + c.bench( + &format!("vec_of_{}_struct", n), + Benchmark::new("from_ssz_bytes", move |b| { + b.iter_with_setup( + || bytes.clone(), + |bytes| { + let vec: Vec = Vec::from_ssz_bytes(&bytes).unwrap(); + black_box(vec) + }, + ) + }) + .sample_size(100), + ); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/eth2/utils/ssz/examples/large_list.rs b/eth2/utils/ssz/examples/large_list.rs new file mode 100644 index 000000000..618603604 --- /dev/null +++ b/eth2/utils/ssz/examples/large_list.rs @@ -0,0 +1,16 @@ +//! Encode and decode a list many times. +//! +//! Useful for `cargo flamegraph`. + +use ssz::{Decode, Encode}; + +fn main() { + let vec: Vec = vec![4242; 8196]; + + let output: Vec> = (0..40_000) + .into_iter() + .map(|_| Vec::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap()) + .collect(); + + println!("{}", output.len()); +} diff --git a/eth2/utils/ssz/examples/large_list_of_structs.rs b/eth2/utils/ssz/examples/large_list_of_structs.rs new file mode 100644 index 000000000..2924541ea --- /dev/null +++ b/eth2/utils/ssz/examples/large_list_of_structs.rs @@ -0,0 +1,32 @@ +//! Encode and decode a list many times. +//! +//! Useful for `cargo flamegraph`. + +use ssz::{Decode, Encode}; +use ssz_derive::{Decode, Encode}; + +#[derive(Clone, Copy, Encode, Decode)] +pub struct FixedLen { + a: u64, + b: u64, + c: u64, + d: u64, +} + +fn main() { + let fixed_len = FixedLen { + a: 42, + b: 42, + c: 42, + d: 42, + }; + + let vec: Vec = vec![fixed_len; 8196]; + + let output: Vec> = (0..40_000) + .into_iter() + .map(|_| Vec::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap()) + .collect(); + + println!("{}", output.len()); +} diff --git a/eth2/utils/ssz/examples/struct_definition.rs b/eth2/utils/ssz/examples/struct_definition.rs new file mode 100644 index 000000000..fa3ed2a64 --- /dev/null +++ b/eth2/utils/ssz/examples/struct_definition.rs @@ -0,0 +1,66 @@ +use ssz::{Decode, DecodeError, Encode, SszDecoderBuilder, SszEncoder}; + +#[derive(Debug, PartialEq)] +pub struct Foo { + a: u16, + b: Vec, + c: u16, +} + +impl Encode for Foo { + fn is_ssz_fixed_len() -> bool { + ::is_ssz_fixed_len() && as Encode>::is_ssz_fixed_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + let offset = ::ssz_fixed_len() + + as Encode>::ssz_fixed_len() + + ::ssz_fixed_len(); + + let mut encoder = SszEncoder::container(buf, offset); + + encoder.append(&self.a); + encoder.append(&self.b); + encoder.append(&self.c); + + encoder.finalize(); + } +} + +impl Decode for Foo { + fn is_ssz_fixed_len() -> bool { + ::is_ssz_fixed_len() && as Decode>::is_ssz_fixed_len() + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let mut builder = SszDecoderBuilder::new(bytes); + + builder.register_type::()?; + builder.register_type::>()?; + builder.register_type::()?; + + let mut decoder = builder.build()?; + + Ok(Self { + a: decoder.decode_next()?, + b: decoder.decode_next()?, + c: decoder.decode_next()?, + }) + } +} + +fn main() { + let foo = Foo { + a: 42, + b: vec![0, 1, 2, 3], + c: 11, + }; + + let bytes = vec![42, 0, 8, 0, 0, 0, 11, 0, 0, 1, 2, 3]; + + assert_eq!(foo.as_ssz_bytes(), bytes); + + let decoded_foo = Foo::from_ssz_bytes(&bytes).unwrap(); + + assert_eq!(foo, decoded_foo); +} diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index 7ed6fe491..891104733 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -1,215 +1,248 @@ -use super::LENGTH_BYTES; +use super::*; +pub mod impls; + +/// Returned when SSZ decoding fails. #[derive(Debug, PartialEq)] pub enum DecodeError { - TooShort, - TooLong, - Invalid, + /// The bytes supplied were too short to be decoded into the specified type. + InvalidByteLength { len: usize, expected: usize }, + /// The given bytes were too short to be read as a length prefix. + InvalidLengthPrefix { len: usize, expected: usize }, + /// A length offset pointed to a byte that was out-of-bounds (OOB). + /// + /// A bytes may be OOB for the following reasons: + /// + /// - It is `>= bytes.len()`. + /// - When decoding variable length items, the 1st offset points "backwards" into the fixed + /// length items (i.e., `length[0] < BYTES_PER_LENGTH_OFFSET`). + /// - When decoding variable-length items, the `n`'th offset was less than the `n-1`'th offset. + OutOfBoundsByte { i: usize }, + /// The given bytes were invalid for some application-level reason. + BytesInvalid(String), } -pub trait Decodable: Sized { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError>; -} - -/// Decode the given bytes for the given type +/// Provides SSZ decoding (de-serialization) via the `from_ssz_bytes(&bytes)` method. /// -/// The single ssz encoded value/container/list will be decoded as the given type, -/// by recursively calling `ssz_decode`. -/// Check on totality for underflowing the length of bytes and overflow checks done per container -pub fn decode(ssz_bytes: &[u8]) -> Result<(T), DecodeError> -where - T: Decodable, -{ - let (decoded, i): (T, usize) = match T::ssz_decode(ssz_bytes, 0) { - Err(e) => return Err(e), - Ok(v) => v, - }; +/// See `examples/` for manual implementations or the crate root for implementations using +/// `#[derive(Decode)]`. +pub trait Decode: Sized { + /// Returns `true` if this object has a fixed-length. + /// + /// I.e., there are no variable length items in this object or any of it's contained objects. + fn is_ssz_fixed_len() -> bool; - if i < ssz_bytes.len() { - return Err(DecodeError::TooLong); + /// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes. + /// + /// By default, this is set to `BYTES_PER_LENGTH_OFFSET` which is suitable for variable length + /// objects, but not fixed-length objects. Fixed-length objects _must_ return a value which + /// represents their length. + fn ssz_fixed_len() -> usize { + BYTES_PER_LENGTH_OFFSET } - Ok(decoded) + /// Attempts to decode `Self` from `bytes`, returning a `DecodeError` on failure. + /// + /// The supplied bytes must be the exact length required to decode `Self`, excess bytes will + /// result in an error. + fn from_ssz_bytes(bytes: &[u8]) -> Result; } -/// Decode a vector (list) of encoded bytes. +#[derive(Copy, Clone, Debug)] +pub struct Offset { + position: usize, + offset: usize, +} + +/// Builds an `SszDecoder`. /// -/// Each element in the list will be decoded and placed into the vector. -pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) -> Result<(Vec, usize), DecodeError> -where - T: Decodable, -{ - if index + LENGTH_BYTES > ssz_bytes.len() { - return Err(DecodeError::TooShort); - }; - - // get the length - let serialized_length = match decode_length(ssz_bytes, index, LENGTH_BYTES) { - Err(v) => return Err(v), - Ok(v) => v, - }; - - let final_len: usize = index + LENGTH_BYTES + serialized_length; - - if final_len > ssz_bytes.len() { - return Err(DecodeError::TooShort); - }; - - let mut tmp_index = index + LENGTH_BYTES; - let mut res_vec: Vec = Vec::new(); - - while tmp_index < final_len { - match T::ssz_decode(ssz_bytes, tmp_index) { - Err(v) => return Err(v), - Ok(v) => { - tmp_index = v.1; - res_vec.push(v.0); - } - }; - } - - Ok((res_vec, final_len)) +/// The purpose of this struct is to split some SSZ bytes into individual slices. The builder is +/// then converted into a `SszDecoder` which decodes those values into object instances. +/// +/// See [`SszDecoder`](struct.SszDecoder.html) for usage examples. +pub struct SszDecoderBuilder<'a> { + bytes: &'a [u8], + items: Vec<&'a [u8]>, + offsets: Vec, + items_index: usize, } -/// Given some number of bytes, interpret the first four -/// bytes as a 32-bit little-endian integer and return the -/// result. -pub fn decode_length( - bytes: &[u8], - index: usize, - length_bytes: usize, -) -> Result { - if bytes.len() < index + length_bytes { - return Err(DecodeError::TooShort); - }; - let mut len: usize = 0; - for (i, byte) in bytes - .iter() - .enumerate() - .take(index + length_bytes) - .skip(index) - { - let offset = (i - index) * 8; - len |= (*byte as usize) << offset; - } - Ok(len) -} - -#[cfg(test)] -mod tests { - use super::super::encode::*; - use super::*; - - #[test] - fn test_ssz_decode_length() { - let decoded = decode_length(&vec![1, 0, 0, 0], 0, LENGTH_BYTES); - assert_eq!(decoded.unwrap(), 1); - - let decoded = decode_length(&vec![0, 1, 0, 0], 0, LENGTH_BYTES); - assert_eq!(decoded.unwrap(), 256); - - let decoded = decode_length(&vec![255, 1, 0, 0], 0, LENGTH_BYTES); - assert_eq!(decoded.unwrap(), 511); - - let decoded = decode_length(&vec![255, 255, 255, 255], 0, LENGTH_BYTES); - assert_eq!(decoded.unwrap(), 4294967295); - } - - #[test] - fn test_encode_decode_length() { - let params: Vec = vec![ - 0, - 1, - 2, - 3, - 7, - 8, - 16, - 2 ^ 8, - 2 ^ 8 + 1, - 2 ^ 16, - 2 ^ 16 + 1, - 2 ^ 24, - 2 ^ 24 + 1, - 2 ^ 32, - ]; - for i in params { - let decoded = decode_length(&encode_length(i, LENGTH_BYTES), 0, LENGTH_BYTES).unwrap(); - assert_eq!(i, decoded); +impl<'a> SszDecoderBuilder<'a> { + /// Instantiate a new builder that should build a `SszDecoder` over the given `bytes` which + /// are assumed to be the SSZ encoding of some object. + pub fn new(bytes: &'a [u8]) -> Self { + Self { + bytes, + items: vec![], + offsets: vec![], + items_index: 0, } } - #[test] - fn test_encode_decode_ssz_list() { - let test_vec: Vec = vec![256; 12]; - let mut stream = SszStream::new(); - stream.append_vec(&test_vec); - let ssz = stream.drain(); + /// Declares that some type `T` is the next item in `bytes`. + pub fn register_type(&mut self) -> Result<(), DecodeError> { + if T::is_ssz_fixed_len() { + let start = self.items_index; + self.items_index += T::ssz_fixed_len(); - // u16 - let decoded: (Vec, usize) = decode_ssz_list(&ssz, 0).unwrap(); + let slice = self.bytes.get(start..self.items_index).ok_or_else(|| { + DecodeError::InvalidByteLength { + len: self.bytes.len(), + expected: self.items_index, + } + })?; - assert_eq!(decoded.0, test_vec); - assert_eq!(decoded.1, LENGTH_BYTES + (12 * 2)); + self.items.push(slice); + } else { + let offset = read_offset(&self.bytes[self.items_index..])?; + + let previous_offset = self + .offsets + .last() + .and_then(|o| Some(o.offset)) + .unwrap_or_else(|| BYTES_PER_LENGTH_OFFSET); + + if previous_offset > offset { + return Err(DecodeError::OutOfBoundsByte { i: offset }); + } else if offset > self.bytes.len() { + return Err(DecodeError::OutOfBoundsByte { i: offset }); + } + + self.offsets.push(Offset { + position: self.items.len(), + offset, + }); + + // Push an empty slice into items; it will be replaced later. + self.items.push(&[]); + + self.items_index += BYTES_PER_LENGTH_OFFSET; + } + + Ok(()) } - #[test] - fn test_decode_ssz_list() { - // u16 - let v: Vec = vec![10, 10, 10, 10]; - let decoded: (Vec, usize) = - decode_ssz_list(&vec![8, 0, 0, 0, 10, 0, 10, 0, 10, 0, 10, 0], 0).unwrap(); + fn finalize(&mut self) -> Result<(), DecodeError> { + if !self.offsets.is_empty() { + // Check to ensure the first offset points to the byte immediately following the + // fixed-length bytes. + if self.offsets[0].offset != self.items_index { + return Err(DecodeError::OutOfBoundsByte { + i: self.offsets[0].offset, + }); + } - assert_eq!(decoded.0, v); - assert_eq!(decoded.1, LENGTH_BYTES + (4 * 2)); + // Iterate through each pair of offsets, grabbing the slice between each of the offsets. + for pair in self.offsets.windows(2) { + let a = pair[0]; + let b = pair[1]; - // u32 - let v: Vec = vec![10, 10, 10, 10]; - let decoded: (Vec, usize) = decode_ssz_list( - &vec![ - 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 00, - ], - 0, - ) - .unwrap(); - assert_eq!(decoded.0, v); - assert_eq!(decoded.1, 20); + self.items[a.position] = &self.bytes[a.offset..b.offset]; + } - // u64 - let v: Vec = vec![10, 10, 10, 10]; - let decoded: (Vec, usize) = decode_ssz_list( - &vec![ - 32, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, - 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, - ], - 0, - ) - .unwrap(); - assert_eq!(decoded.0, v); - assert_eq!(decoded.1, LENGTH_BYTES + (8 * 4)); + // Handle the last offset, pushing a slice from it's start through to the end of + // `self.bytes`. + if let Some(last) = self.offsets.last() { + self.items[last.position] = &self.bytes[last.offset..] + } + } else { + // If the container is fixed-length, ensure there are no excess bytes. + if self.items_index != self.bytes.len() { + return Err(DecodeError::InvalidByteLength { + len: self.bytes.len(), + expected: self.items_index, + }); + } + } - // Check that it can accept index - let v: Vec = vec![15, 15, 15, 15]; - let offset = 10; - let decoded: (Vec, usize) = decode_ssz_list( - &vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, - ], - offset, - ) - .unwrap(); - assert_eq!(decoded.0, v); - assert_eq!(decoded.1, offset + LENGTH_BYTES + (8 * 4)); + Ok(()) + } - // Check that length > bytes throws error - let decoded: Result<(Vec, usize), DecodeError> = - decode_ssz_list(&vec![32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0], 0); - assert_eq!(decoded, Err(DecodeError::TooShort)); + /// Finalizes the builder, returning a `SszDecoder` that may be used to instantiate objects. + pub fn build(mut self) -> Result, DecodeError> { + self.finalize()?; - // Check that incorrect index throws error - let decoded: Result<(Vec, usize), DecodeError> = - decode_ssz_list(&vec![15, 0, 0, 0, 0, 0, 0, 0], 16); - assert_eq!(decoded, Err(DecodeError::TooShort)); + Ok(SszDecoder { items: self.items }) + } +} + +/// Decodes some slices of SSZ into object instances. Should be instantiated using +/// [`SszDecoderBuilder`](struct.SszDecoderBuilder.html). +/// +/// ## Example +/// +/// ```rust +/// use ssz_derive::{Encode, Decode}; +/// use ssz::{Decode, Encode, SszDecoder, SszDecoderBuilder}; +/// +/// #[derive(PartialEq, Debug, Encode, Decode)] +/// struct Foo { +/// a: u64, +/// b: Vec, +/// } +/// +/// fn main() { +/// let foo = Foo { +/// a: 42, +/// b: vec![1, 3, 3, 7] +/// }; +/// +/// let bytes = foo.as_ssz_bytes(); +/// +/// let mut builder = SszDecoderBuilder::new(&bytes); +/// +/// builder.register_type::().unwrap(); +/// builder.register_type::>().unwrap(); +/// +/// let mut decoder = builder.build().unwrap(); +/// +/// let decoded_foo = Foo { +/// a: decoder.decode_next().unwrap(), +/// b: decoder.decode_next().unwrap(), +/// }; +/// +/// assert_eq!(foo, decoded_foo); +/// } +/// +/// ``` +pub struct SszDecoder<'a> { + items: Vec<&'a [u8]>, +} + +impl<'a> SszDecoder<'a> { + /// Decodes the next item. + /// + /// # Panics + /// + /// Panics when attempting to decode more items than actually exist. + pub fn decode_next(&mut self) -> Result { + T::from_ssz_bytes(self.items.remove(0)) + } +} + +/// Reads a `BYTES_PER_LENGTH_OFFSET`-byte length from `bytes`, where `bytes.len() >= +/// BYTES_PER_LENGTH_OFFSET`. +fn read_offset(bytes: &[u8]) -> Result { + decode_offset(bytes.get(0..BYTES_PER_LENGTH_OFFSET).ok_or_else(|| { + DecodeError::InvalidLengthPrefix { + len: bytes.len(), + expected: BYTES_PER_LENGTH_OFFSET, + } + })?) +} + +/// Decode bytes as a little-endian usize, returning an `Err` if `bytes.len() != +/// BYTES_PER_LENGTH_OFFSET`. +fn decode_offset(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = BYTES_PER_LENGTH_OFFSET; + + if len != expected { + Err(DecodeError::InvalidLengthPrefix { len, expected }) + } else { + let mut array: [u8; BYTES_PER_LENGTH_OFFSET] = std::default::Default::default(); + array.clone_from_slice(bytes); + + Ok(u32::from_le_bytes(array) as usize) } } diff --git a/eth2/utils/ssz/src/decode/impls.rs b/eth2/utils/ssz/src/decode/impls.rs new file mode 100644 index 000000000..8a5a36780 --- /dev/null +++ b/eth2/utils/ssz/src/decode/impls.rs @@ -0,0 +1,422 @@ +use super::*; +use ethereum_types::H256; + +macro_rules! impl_decodable_for_uint { + ($type: ident, $bit_size: expr) => { + impl Decode for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $bit_size / 8 + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(DecodeError::InvalidByteLength { len, expected }) + } else { + let mut array: [u8; $bit_size / 8] = std::default::Default::default(); + array.clone_from_slice(bytes); + + Ok(Self::from_le_bytes(array)) + } + } + } + }; +} + +impl_decodable_for_uint!(u8, 8); +impl_decodable_for_uint!(u16, 16); +impl_decodable_for_uint!(u32, 32); +impl_decodable_for_uint!(u64, 64); +impl_decodable_for_uint!(usize, 64); + +impl Decode for bool { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + 1 + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(DecodeError::InvalidByteLength { len, expected }) + } else { + match bytes[0] { + 0b0000_0000 => Ok(false), + 0b0000_0001 => Ok(true), + _ => { + return Err(DecodeError::BytesInvalid( + format!("Out-of-range for boolean: {}", bytes[0]).to_string(), + )) + } + } + } + } +} + +impl Decode for H256 { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + 32 + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(DecodeError::InvalidByteLength { len, expected }) + } else { + Ok(H256::from_slice(bytes)) + } + } +} + +macro_rules! impl_decodable_for_u8_array { + ($len: expr) => { + impl Decode for [u8; $len] { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $len + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(DecodeError::InvalidByteLength { len, expected }) + } else { + let mut array: [u8; $len] = [0; $len]; + array.copy_from_slice(&bytes[..]); + + Ok(array) + } + } + } + }; +} + +impl_decodable_for_u8_array!(4); + +impl Decode for Vec { + fn is_ssz_fixed_len() -> bool { + false + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + if bytes.len() == 0 { + Ok(vec![]) + } else if T::is_ssz_fixed_len() { + bytes + .chunks(T::ssz_fixed_len()) + .map(|chunk| T::from_ssz_bytes(chunk)) + .collect() + } else { + decode_list_of_variable_length_items(bytes) + } + } +} + +/// Decodes `bytes` as if it were a list of variable-length items. +/// +/// The `ssz::SszDecoder` can also perform this functionality, however it it significantly faster +/// as it is optimized to read same-typed items whilst `ssz::SszDecoder` supports reading items of +/// differing types. +pub fn decode_list_of_variable_length_items( + bytes: &[u8], +) -> Result, DecodeError> { + let mut next_variable_byte = read_offset(bytes)?; + + // The value of the first offset must not point back into the same bytes that defined + // it. + if next_variable_byte < BYTES_PER_LENGTH_OFFSET { + return Err(DecodeError::OutOfBoundsByte { + i: next_variable_byte, + }); + } + + let num_items = next_variable_byte / BYTES_PER_LENGTH_OFFSET; + + // The fixed-length section must be a clean multiple of `BYTES_PER_LENGTH_OFFSET`. + if next_variable_byte != num_items * BYTES_PER_LENGTH_OFFSET { + return Err(DecodeError::InvalidByteLength { + len: next_variable_byte, + expected: num_items * BYTES_PER_LENGTH_OFFSET, + }); + } + + let mut values = Vec::with_capacity(num_items); + for i in 1..=num_items { + let slice_option = if i == num_items { + bytes.get(next_variable_byte..) + } else { + let offset = read_offset(&bytes[(i * BYTES_PER_LENGTH_OFFSET)..])?; + + let start = next_variable_byte; + next_variable_byte = offset; + + bytes.get(start..next_variable_byte) + }; + + let slice = slice_option.ok_or_else(|| DecodeError::OutOfBoundsByte { + i: next_variable_byte, + })?; + + values.push(T::from_ssz_bytes(slice)?); + } + + Ok(values) +} + +#[cfg(test)] +mod tests { + use super::*; + + // Note: decoding of valid bytes is generally tested "indirectly" in the `/tests` dir, by + // encoding then decoding the element. + + #[test] + fn invalid_u8_array_4() { + assert_eq!( + <[u8; 4]>::from_ssz_bytes(&[0; 3]), + Err(DecodeError::InvalidByteLength { + len: 3, + expected: 4 + }) + ); + + assert_eq!( + <[u8; 4]>::from_ssz_bytes(&[0; 5]), + Err(DecodeError::InvalidByteLength { + len: 5, + expected: 4 + }) + ); + } + + #[test] + fn invalid_bool() { + assert_eq!( + bool::from_ssz_bytes(&[0; 2]), + Err(DecodeError::InvalidByteLength { + len: 2, + expected: 1 + }) + ); + + assert_eq!( + bool::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + len: 0, + expected: 1 + }) + ); + + if let Err(DecodeError::BytesInvalid(_)) = bool::from_ssz_bytes(&[2]) { + // Success. + } else { + panic!("Did not return error on invalid bool val") + } + } + + #[test] + fn invalid_h256() { + assert_eq!( + H256::from_ssz_bytes(&[0; 33]), + Err(DecodeError::InvalidByteLength { + len: 33, + expected: 32 + }) + ); + + assert_eq!( + H256::from_ssz_bytes(&[0; 31]), + Err(DecodeError::InvalidByteLength { + len: 31, + expected: 32 + }) + ); + } + + #[test] + fn first_length_points_backwards() { + assert_eq!( + >>::from_ssz_bytes(&[0, 0, 0, 0]), + Err(DecodeError::OutOfBoundsByte { i: 0 }) + ); + + assert_eq!( + >>::from_ssz_bytes(&[1, 0, 0, 0]), + Err(DecodeError::OutOfBoundsByte { i: 1 }) + ); + + assert_eq!( + >>::from_ssz_bytes(&[2, 0, 0, 0]), + Err(DecodeError::OutOfBoundsByte { i: 2 }) + ); + + assert_eq!( + >>::from_ssz_bytes(&[3, 0, 0, 0]), + Err(DecodeError::OutOfBoundsByte { i: 3 }) + ); + } + + #[test] + fn lengths_are_decreasing() { + assert_eq!( + >>::from_ssz_bytes(&[12, 0, 0, 0, 14, 0, 0, 0, 12, 0, 0, 0, 1, 0, 1, 0]), + Err(DecodeError::OutOfBoundsByte { i: 12 }) + ); + } + + #[test] + fn awkward_fixed_lenth_portion() { + assert_eq!( + >>::from_ssz_bytes(&[10, 0, 0, 0, 10, 0, 0, 0, 0, 0]), + Err(DecodeError::InvalidByteLength { + len: 10, + expected: 8 + }) + ); + } + + #[test] + fn length_out_of_bounds() { + assert_eq!( + >>::from_ssz_bytes(&[5, 0, 0, 0]), + Err(DecodeError::InvalidByteLength { + len: 5, + expected: 4 + }) + ); + assert_eq!( + >>::from_ssz_bytes(&[8, 0, 0, 0, 9, 0, 0, 0]), + Err(DecodeError::OutOfBoundsByte { i: 9 }) + ); + } + + #[test] + fn vec_of_vec_of_u16() { + assert_eq!( + >>::from_ssz_bytes(&[4, 0, 0, 0]), + Ok(vec![vec![]]) + ); + + assert_eq!( + >::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]), + Ok(vec![0, 1, 2, 3]) + ); + assert_eq!(::from_ssz_bytes(&[16, 0]), Ok(16)); + assert_eq!(::from_ssz_bytes(&[0, 1]), Ok(256)); + assert_eq!(::from_ssz_bytes(&[255, 255]), Ok(65535)); + + assert_eq!( + ::from_ssz_bytes(&[255]), + Err(DecodeError::InvalidByteLength { + len: 1, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + len: 0, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[0, 1, 2]), + Err(DecodeError::InvalidByteLength { + len: 3, + expected: 2 + }) + ); + } + + #[test] + fn vec_of_u16() { + assert_eq!(>::from_ssz_bytes(&[0, 0, 0, 0]), Ok(vec![0, 0])); + assert_eq!( + >::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]), + Ok(vec![0, 1, 2, 3]) + ); + assert_eq!(::from_ssz_bytes(&[16, 0]), Ok(16)); + assert_eq!(::from_ssz_bytes(&[0, 1]), Ok(256)); + assert_eq!(::from_ssz_bytes(&[255, 255]), Ok(65535)); + + assert_eq!( + ::from_ssz_bytes(&[255]), + Err(DecodeError::InvalidByteLength { + len: 1, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + len: 0, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[0, 1, 2]), + Err(DecodeError::InvalidByteLength { + len: 3, + expected: 2 + }) + ); + } + + #[test] + fn u16() { + assert_eq!(::from_ssz_bytes(&[0, 0]), Ok(0)); + assert_eq!(::from_ssz_bytes(&[16, 0]), Ok(16)); + assert_eq!(::from_ssz_bytes(&[0, 1]), Ok(256)); + assert_eq!(::from_ssz_bytes(&[255, 255]), Ok(65535)); + + assert_eq!( + ::from_ssz_bytes(&[255]), + Err(DecodeError::InvalidByteLength { + len: 1, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + len: 0, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[0, 1, 2]), + Err(DecodeError::InvalidByteLength { + len: 3, + expected: 2 + }) + ); + } +} diff --git a/eth2/utils/ssz/src/encode.rs b/eth2/utils/ssz/src/encode.rs index e1484c4c4..257ece2a2 100644 --- a/eth2/utils/ssz/src/encode.rs +++ b/eth2/utils/ssz/src/encode.rs @@ -1,85 +1,159 @@ -use super::LENGTH_BYTES; +use super::*; -pub trait Encodable { - fn ssz_append(&self, s: &mut SszStream); -} +mod impls; -/// Provides a buffer for appending ssz-encodable values. +/// Provides SSZ encoding (serialization) via the `as_ssz_bytes(&self)` method. /// -/// Use the `append()` fn to add a value to a list, then use -/// the `drain()` method to consume the struct and return the -/// ssz encoded bytes. -#[derive(Default)] -pub struct SszStream { - buffer: Vec, +/// See `examples/` for manual implementations or the crate root for implementations using +/// `#[derive(Encode)]`. +pub trait Encode { + /// Returns `true` if this object has a fixed-length. + /// + /// I.e., there are no variable length items in this object or any of it's contained objects. + fn is_ssz_fixed_len() -> bool; + + /// Append the encoding `self` to `buf`. + /// + /// Note, variable length objects need only to append their "variable length" portion, they do + /// not need to provide their offset. + fn ssz_append(&self, buf: &mut Vec); + + /// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes. + /// + /// By default, this is set to `BYTES_PER_LENGTH_OFFSET` which is suitable for variable length + /// objects, but not fixed-length objects. Fixed-length objects _must_ return a value which + /// represents their length. + fn ssz_fixed_len() -> usize { + BYTES_PER_LENGTH_OFFSET + } + + /// Returns the full-form encoding of this object. + /// + /// The default implementation of this method should suffice for most cases. + fn as_ssz_bytes(&self) -> Vec { + let mut buf = vec![]; + + self.ssz_append(&mut buf); + + buf + } } -impl SszStream { - /// Create a new, empty stream for writing ssz values. - pub fn new() -> Self { - SszStream { buffer: Vec::new() } - } +/// Allow for encoding an ordered series of distinct or indistinct objects as SSZ bytes. +/// +/// **You must call `finalize(..)` after the final `append(..)` call** to ensure the bytes are +/// written to `buf`. +/// +/// ## Example +/// +/// Use `SszEncoder` to produce identical output to `foo.as_ssz_bytes()`: +/// +/// ```rust +/// use ssz_derive::{Encode, Decode}; +/// use ssz::{Decode, Encode, SszEncoder}; +/// +/// #[derive(PartialEq, Debug, Encode, Decode)] +/// struct Foo { +/// a: u64, +/// b: Vec, +/// } +/// +/// fn main() { +/// let foo = Foo { +/// a: 42, +/// b: vec![1, 3, 3, 7] +/// }; +/// +/// let mut buf: Vec = vec![]; +/// let offset = ::ssz_fixed_len() + as Encode>::ssz_fixed_len(); +/// +/// let mut encoder = SszEncoder::container(&mut buf, offset); +/// +/// encoder.append(&foo.a); +/// encoder.append(&foo.b); +/// +/// encoder.finalize(); +/// +/// assert_eq!(foo.as_ssz_bytes(), buf); +/// } +/// +/// ``` +pub struct SszEncoder<'a> { + offset: usize, + buf: &'a mut Vec, + variable_bytes: Vec, +} - /// Append some ssz encodable value to the stream. - pub fn append(&mut self, value: &E) -> &mut Self - where - E: Encodable, - { - value.ssz_append(self); - self - } - - /// Append some ssz encoded bytes to the stream. +impl<'a> SszEncoder<'a> { + /// Instantiate a new encoder for encoding a SSZ list. /// - /// The length of the supplied bytes will be concatenated - /// to the stream before the supplied bytes. - pub fn append_encoded_val(&mut self, vec: &[u8]) { - self.buffer - .extend_from_slice(&encode_length(vec.len(), LENGTH_BYTES)); - self.buffer.extend_from_slice(&vec); + /// Identical to `Self::container`. + pub fn list(buf: &'a mut Vec, num_fixed_bytes: usize) -> Self { + Self::container(buf, num_fixed_bytes) } - /// Append some ssz encoded bytes to the stream without calculating length - /// - /// The raw bytes will be concatenated to the stream. - pub fn append_encoded_raw(&mut self, vec: &[u8]) { - self.buffer.extend_from_slice(&vec); - } + /// Instantiate a new encoder for encoding a SSZ container. + pub fn container(buf: &'a mut Vec, num_fixed_bytes: usize) -> Self { + buf.reserve(num_fixed_bytes); - /// Append some vector (list) of encodable values to the stream. - /// - /// The length of the list will be concatenated to the stream, then - /// each item in the vector will be encoded and concatenated. - pub fn append_vec(&mut self, vec: &[E]) - where - E: Encodable, - { - let mut list_stream = SszStream::new(); - for item in vec { - item.ssz_append(&mut list_stream); + Self { + offset: num_fixed_bytes, + buf, + variable_bytes: vec![], } - self.append_encoded_val(&list_stream.drain()); } - /// Consume the stream and return the underlying bytes. - pub fn drain(self) -> Vec { - self.buffer + /// Append some `item` to the SSZ bytes. + pub fn append(&mut self, item: &T) { + if T::is_ssz_fixed_len() { + item.ssz_append(&mut self.buf); + } else { + self.buf + .append(&mut encode_length(self.offset + self.variable_bytes.len())); + + item.ssz_append(&mut self.variable_bytes); + } + } + + /// Write the variable bytes to `self.bytes`. + /// + /// This method must be called after the final `append(..)` call when serializing + /// variable-length items. + pub fn finalize(&mut self) -> &mut Vec { + self.buf.append(&mut self.variable_bytes); + + &mut self.buf } } -/// Encode some length into a ssz size prefix. +/// Encode `len` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length. /// -/// The ssz size prefix is 4 bytes, which is treated as a continuious -/// 32bit little-endian integer. -pub fn encode_length(len: usize, length_bytes: usize) -> Vec { - assert!(length_bytes > 0); // For sanity - assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8)); - let mut header: Vec = vec![0; length_bytes]; - for (i, header_byte) in header.iter_mut().enumerate() { - let offset = i * 8; - *header_byte = ((len >> offset) & 0xff) as u8; - } - header +/// If `len` is larger than `2 ^ BYTES_PER_LENGTH_OFFSET`, a `debug_assert` is raised. +pub fn encode_length(len: usize) -> Vec { + // Note: it is possible for `len` to be larger than what can be encoded in + // `BYTES_PER_LENGTH_OFFSET` bytes, triggering this debug assertion. + // + // These are the alternatives to using a `debug_assert` here: + // + // 1. Use `assert`. + // 2. Push an error to the caller (e.g., `Option` or `Result`). + // 3. Ignore it completely. + // + // I have avoided (1) because it's basically a choice between "produce invalid SSZ" or "kill + // the entire program". I figure it may be possible for an attacker to trigger this assert and + // take the program down -- I think producing invalid SSZ is a better option than this. + // + // I have avoided (2) because this error will need to be propagated upstream, making encoding a + // function which may fail. I don't think this is ergonomic and the upsides don't outweigh the + // downsides. + // + // I figure a `debug_assertion` is better than (3) as it will give us a change to detect the + // error during testing. + // + // If you have a different opinion, feel free to start an issue and tag @paulhauner. + debug_assert!(len <= MAX_LENGTH_VALUE); + + len.to_le_bytes()[0..BYTES_PER_LENGTH_OFFSET].to_vec() } #[cfg(test)] @@ -87,84 +161,27 @@ mod tests { use super::*; #[test] - #[should_panic] - fn test_encode_length_0_bytes_panic() { - encode_length(0, 0); - } + fn test_encode_length() { + assert_eq!(encode_length(0), vec![0; 4]); + + assert_eq!(encode_length(1), vec![1, 0, 0, 0]); - #[test] - fn test_encode_length_4_bytes() { - assert_eq!(encode_length(0, LENGTH_BYTES), vec![0; 4]); - assert_eq!(encode_length(1, LENGTH_BYTES), vec![1, 0, 0, 0]); - assert_eq!(encode_length(255, LENGTH_BYTES), vec![255, 0, 0, 0]); - assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 1, 0, 0]); assert_eq!( - encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1 - vec![255, 255, 255, 255] + encode_length(MAX_LENGTH_VALUE), + vec![255; BYTES_PER_LENGTH_OFFSET] ); } - #[test] - fn test_encode_lower_length() { - assert_eq!(encode_length(0, LENGTH_BYTES - 2), vec![0; 2]); - assert_eq!(encode_length(1, LENGTH_BYTES - 2), vec![1, 0]); - } - - #[test] - fn test_encode_higher_length() { - assert_eq!(encode_length(0, LENGTH_BYTES + 2), vec![0; 6]); - assert_eq!(encode_length(1, LENGTH_BYTES + 2), vec![1, 0, 0, 0, 0, 0]); - } - #[test] #[should_panic] - fn test_encode_length_4_bytes_panic() { - encode_length(4294967296, LENGTH_BYTES); // 2^(3*8) + #[cfg(debug_assertions)] + fn test_encode_length_above_max_debug_panics() { + encode_length(MAX_LENGTH_VALUE + 1); } #[test] - fn test_encode_list() { - let test_vec: Vec = vec![256; 12]; - let mut stream = SszStream::new(); - stream.append_vec(&test_vec); - let ssz = stream.drain(); - - assert_eq!(ssz.len(), LENGTH_BYTES + (12 * 2)); - assert_eq!(ssz[0..4], *vec![24, 0, 0, 0]); - assert_eq!(ssz[4..6], *vec![0, 1]); - } - - #[test] - fn test_encode_mixed_prefixed() { - let test_vec: Vec = vec![100, 200]; - let test_value: u8 = 5; - - let mut stream = SszStream::new(); - stream.append_vec(&test_vec); - stream.append(&test_value); - let ssz = stream.drain(); - - assert_eq!(ssz.len(), LENGTH_BYTES + (2 * 2) + 1); - assert_eq!(ssz[0..4], *vec![4, 0, 0, 0]); - assert_eq!(ssz[4..6], *vec![100, 0]); - assert_eq!(ssz[6..8], *vec![200, 0]); - assert_eq!(ssz[8], 5); - } - - #[test] - fn test_encode_mixed_postfixed() { - let test_value: u8 = 5; - let test_vec: Vec = vec![100, 200]; - - let mut stream = SszStream::new(); - stream.append(&test_value); - stream.append_vec(&test_vec); - let ssz = stream.drain(); - - assert_eq!(ssz.len(), 1 + LENGTH_BYTES + (2 * 2)); - assert_eq!(ssz[0], 5); - assert_eq!(ssz[1..5], *vec![4, 0, 0, 0]); - assert_eq!(ssz[5..7], *vec![100, 0]); - assert_eq!(ssz[7..9], *vec![200, 0]); + #[cfg(not(debug_assertions))] + fn test_encode_length_above_max_not_debug_does_not_panic() { + assert_eq!(encode_length(MAX_LENGTH_VALUE + 1), vec![0; 4]); } } diff --git a/eth2/utils/ssz/src/encode/impls.rs b/eth2/utils/ssz/src/encode/impls.rs new file mode 100644 index 000000000..07886d68f --- /dev/null +++ b/eth2/utils/ssz/src/encode/impls.rs @@ -0,0 +1,202 @@ +use super::*; +use ethereum_types::H256; + +macro_rules! impl_encodable_for_uint { + ($type: ident, $bit_size: expr) => { + impl Encode for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $bit_size / 8 + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.extend_from_slice(&self.to_le_bytes()); + } + } + }; +} + +impl_encodable_for_uint!(u8, 8); +impl_encodable_for_uint!(u16, 16); +impl_encodable_for_uint!(u32, 32); +impl_encodable_for_uint!(u64, 64); +impl_encodable_for_uint!(usize, 64); + +impl Encode for Vec { + fn is_ssz_fixed_len() -> bool { + false + } + + fn ssz_append(&self, buf: &mut Vec) { + if T::is_ssz_fixed_len() { + buf.reserve(T::ssz_fixed_len() * self.len()); + + for item in self { + item.ssz_append(buf); + } + } else { + let mut encoder = SszEncoder::list(buf, self.len() * BYTES_PER_LENGTH_OFFSET); + + for item in self { + encoder.append(item); + } + + encoder.finalize(); + } + } +} + +impl Encode for bool { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + 1 + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.extend_from_slice(&(*self as u8).to_le_bytes()); + } +} + +impl Encode for H256 { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + 32 + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.extend_from_slice(self.as_bytes()); + } +} + +macro_rules! impl_encodable_for_u8_array { + ($len: expr) => { + impl Encode for [u8; $len] { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $len + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.extend_from_slice(&self[..]); + } + } + }; +} + +impl_encodable_for_u8_array!(4); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn vec_of_u8() { + let vec: Vec = vec![]; + assert_eq!(vec.as_ssz_bytes(), vec![]); + + let vec: Vec = vec![1]; + assert_eq!(vec.as_ssz_bytes(), vec![1]); + + let vec: Vec = vec![0, 1, 2, 3]; + assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]); + } + + #[test] + fn vec_of_vec_of_u8() { + let vec: Vec> = vec![]; + assert_eq!(vec.as_ssz_bytes(), vec![]); + + let vec: Vec> = vec![vec![]]; + assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]); + + let vec: Vec> = vec![vec![], vec![]]; + assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]); + + let vec: Vec> = vec![vec![0, 1, 2], vec![11, 22, 33]]; + assert_eq!( + vec.as_ssz_bytes(), + vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33] + ); + } + + #[test] + fn ssz_encode_u8() { + assert_eq!(0_u8.as_ssz_bytes(), vec![0]); + assert_eq!(1_u8.as_ssz_bytes(), vec![1]); + assert_eq!(100_u8.as_ssz_bytes(), vec![100]); + assert_eq!(255_u8.as_ssz_bytes(), vec![255]); + } + + #[test] + fn ssz_encode_u16() { + assert_eq!(1_u16.as_ssz_bytes(), vec![1, 0]); + assert_eq!(100_u16.as_ssz_bytes(), vec![100, 0]); + assert_eq!((1_u16 << 8).as_ssz_bytes(), vec![0, 1]); + assert_eq!(65535_u16.as_ssz_bytes(), vec![255, 255]); + } + + #[test] + fn ssz_encode_u32() { + assert_eq!(1_u32.as_ssz_bytes(), vec![1, 0, 0, 0]); + assert_eq!(100_u32.as_ssz_bytes(), vec![100, 0, 0, 0]); + assert_eq!((1_u32 << 16).as_ssz_bytes(), vec![0, 0, 1, 0]); + assert_eq!((1_u32 << 24).as_ssz_bytes(), vec![0, 0, 0, 1]); + assert_eq!((!0_u32).as_ssz_bytes(), vec![255, 255, 255, 255]); + } + + #[test] + fn ssz_encode_u64() { + assert_eq!(1_u64.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!( + (!0_u64).as_ssz_bytes(), + vec![255, 255, 255, 255, 255, 255, 255, 255] + ); + } + + #[test] + fn ssz_encode_usize() { + assert_eq!(1_usize.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!( + (!0_usize).as_ssz_bytes(), + vec![255, 255, 255, 255, 255, 255, 255, 255] + ); + } + + #[test] + fn ssz_encode_bool() { + assert_eq!(true.as_ssz_bytes(), vec![1]); + assert_eq!(false.as_ssz_bytes(), vec![0]); + } + + #[test] + fn ssz_encode_h256() { + assert_eq!(H256::from(&[0; 32]).as_ssz_bytes(), vec![0; 32]); + assert_eq!(H256::from(&[1; 32]).as_ssz_bytes(), vec![1; 32]); + + let bytes = vec![ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]; + + assert_eq!(H256::from_slice(&bytes).as_ssz_bytes(), bytes); + } + + #[test] + fn ssz_encode_u8_array_4() { + assert_eq!([0, 0, 0, 0].as_ssz_bytes(), vec![0; 4]); + assert_eq!([1, 0, 0, 0].as_ssz_bytes(), vec![1, 0, 0, 0]); + assert_eq!([1, 2, 3, 4].as_ssz_bytes(), vec![1, 2, 3, 4]); + } +} diff --git a/eth2/utils/ssz/src/impl_decode.rs b/eth2/utils/ssz/src/impl_decode.rs deleted file mode 100644 index b4a00a12c..000000000 --- a/eth2/utils/ssz/src/impl_decode.rs +++ /dev/null @@ -1,306 +0,0 @@ -use super::decode::decode_ssz_list; -use super::ethereum_types::{Address, H256}; -use super::{Decodable, DecodeError}; - -macro_rules! impl_decodable_for_uint { - ($type: ident, $bit_size: expr) => { - impl Decodable for $type { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - assert!((0 < $bit_size) & ($bit_size <= 64) & ($bit_size % 8 == 0)); - let max_bytes = $bit_size / 8; - if bytes.len() >= (index + max_bytes) { - let end_bytes = index + max_bytes; - let mut result: $type = 0; - for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) { - let offset = (i - index) * 8; - result |= ($type::from(*byte)) << offset; - } - Ok((result, end_bytes)) - } else { - Err(DecodeError::TooShort) - } - } - } - }; -} - -macro_rules! impl_decodable_for_u8_array { - ($len: expr) => { - impl Decodable for [u8; $len] { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index + $len > bytes.len() { - Err(DecodeError::TooShort) - } else { - let mut array: [u8; $len] = [0; $len]; - array.copy_from_slice(&bytes[index..index + $len]); - - Ok((array, index + $len)) - } - } - } - }; -} - -impl_decodable_for_uint!(u16, 16); -impl_decodable_for_uint!(u32, 32); -impl_decodable_for_uint!(u64, 64); -impl_decodable_for_uint!(usize, 64); - -impl_decodable_for_u8_array!(4); - -impl Decodable for u8 { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index >= bytes.len() { - Err(DecodeError::TooShort) - } else { - Ok((bytes[index], index + 1)) - } - } -} - -impl Decodable for bool { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index >= bytes.len() { - Err(DecodeError::TooShort) - } else { - let result = match bytes[index] { - 0b0000_0000 => false, - 0b0000_0001 => true, - _ => return Err(DecodeError::Invalid), - }; - Ok((result, index + 1)) - } - } -} - -impl Decodable for H256 { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() < 32 || bytes.len() - 32 < index { - Err(DecodeError::TooShort) - } else { - Ok((H256::from_slice(&bytes[index..(index + 32)]), index + 32)) - } - } -} - -impl Decodable for Address { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() < 20 || bytes.len() - 20 < index { - Err(DecodeError::TooShort) - } else { - Ok((Address::from_slice(&bytes[index..(index + 20)]), index + 20)) - } - } -} - -impl Decodable for Vec -where - T: Decodable, -{ - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - decode_ssz_list(bytes, index) - } -} - -#[cfg(test)] -mod tests { - use super::super::{decode, DecodeError}; - use super::*; - - #[test] - fn test_ssz_decode_h256() { - /* - * Input is exact length - */ - let input = vec![42_u8; 32]; - let (decoded, i) = H256::ssz_decode(&input, 0).unwrap(); - assert_eq!(decoded.as_bytes(), &input[..]); - assert_eq!(i, 32); - - /* - * Input is too long - */ - let mut input = vec![42_u8; 32]; - input.push(12); - let (decoded, i) = H256::ssz_decode(&input, 0).unwrap(); - assert_eq!(decoded.as_bytes(), &input[0..32]); - assert_eq!(i, 32); - - /* - * Input is too short - */ - let input = vec![42_u8; 31]; - let res = H256::ssz_decode(&input, 0); - assert_eq!(res, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_u16() { - let ssz = vec![0, 0]; - - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 0); - assert_eq!(index, 2); - - let ssz = vec![16, 0]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 16); - assert_eq!(index, 2); - - let ssz = vec![0, 1]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 256); - assert_eq!(index, 2); - - let ssz = vec![255, 255]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 2); - assert_eq!(result, 65535); - - let ssz = vec![1]; - let result: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_u32() { - let ssz = vec![0, 0, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 0); - assert_eq!(index, 4); - - let ssz = vec![0, 1, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 256); - - let ssz = vec![255, 255, 255, 0, 1, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 7); - assert_eq!(result, 256); - - let ssz = vec![0, 1, 200, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 13107456); - - let ssz = vec![255, 255, 255, 255]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 4294967295); - - let ssz = vec![1, 0, 0]; - let result: Result<(u32, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_u64() { - let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 0); - - let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 11); - assert_eq!(result, 18374686479671623680); - - let ssz = vec![0, 0, 0, 0, 0, 0, 0]; - let result: Result<(u64, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_usize() { - let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 0); - - let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 11); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![0, 0, 0, 0, 0, 0, 1]; - let result: Result<(usize, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_decode_ssz_bounds() { - let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![1], 2); - assert_eq!(err, Err(DecodeError::TooShort)); - - let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![0, 0, 0, 0], 3); - assert_eq!(err, Err(DecodeError::TooShort)); - - let result: u16 = <_>::ssz_decode(&vec![0, 0, 0, 1, 0], 3).unwrap().0; - assert_eq!(result, 1); - } - - #[test] - fn test_decode_ssz_bool() { - let ssz = vec![0b0000_0000, 0b0000_0001]; - let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 1); - assert_eq!(result, false); - - let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 1).unwrap(); - assert_eq!(index, 2); - assert_eq!(result, true); - - let ssz = vec![0b0100_0000]; - let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::Invalid)); - - let ssz = vec![]; - let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - #[should_panic] - fn test_decode_ssz_list_underflow() { - // SSZ encoded (u16::[1, 1, 1], u16::2) - let mut encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2, 0]; - let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); - let (decoded_u16, i): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); - assert_eq!(decoded_array, vec![1, 1, 1]); - assert_eq!(decoded_u16, 2); - assert_eq!(i, 12); - - // Underflow - encoded[0] = 4; // change length to 4 from 6 - let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); - let (decoded_u16, _): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); - assert_eq!(decoded_array, vec![1, 1]); - assert_eq!(decoded_u16, 2); - } - - #[test] - fn test_decode_too_long() { - let encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2]; - let decoded_array: Result, DecodeError> = decode(&encoded); - assert_eq!(decoded_array, Err(DecodeError::TooLong)); - } - - #[test] - fn test_decode_u8_array() { - let ssz = vec![0, 1, 2, 3]; - let result: [u8; 4] = decode(&ssz).unwrap(); - assert_eq!(result.len(), 4); - assert_eq!(result, [0, 1, 2, 3]); - } -} diff --git a/eth2/utils/ssz/src/impl_encode.rs b/eth2/utils/ssz/src/impl_encode.rs deleted file mode 100644 index 357dfe60e..000000000 --- a/eth2/utils/ssz/src/impl_encode.rs +++ /dev/null @@ -1,275 +0,0 @@ -extern crate bytes; - -use self::bytes::{BufMut, BytesMut}; -use super::ethereum_types::{Address, H256}; -use super::{Encodable, SszStream}; - -/* - * Note: there is a "to_bytes" function for integers - * in Rust nightly. When it is in stable, we should - * use it instead. - */ -macro_rules! impl_encodable_for_uint { - ($type: ident, $bit_size: expr) => { - impl Encodable for $type { - #[allow(clippy::cast_lossless)] - fn ssz_append(&self, s: &mut SszStream) { - // Ensure bit size is valid - assert!( - (0 < $bit_size) - && ($bit_size % 8 == 0) - && (2_u128.pow($bit_size) > *self as u128) - ); - - // Serialize to bytes - let mut buf = BytesMut::with_capacity($bit_size / 8); - - // Match bit size with encoding - match $bit_size { - 8 => buf.put_u8(*self as u8), - 16 => buf.put_u16_le(*self as u16), - 32 => buf.put_u32_le(*self as u32), - 64 => buf.put_u64_le(*self as u64), - _ => {} - } - - // Append bytes to the SszStream - s.append_encoded_raw(&buf.to_vec()); - } - } - }; -} - -macro_rules! impl_encodable_for_u8_array { - ($len: expr) => { - impl Encodable for [u8; $len] { - fn ssz_append(&self, s: &mut SszStream) { - let bytes: Vec = self.iter().cloned().collect(); - s.append_encoded_raw(&bytes); - } - } - }; -} - -impl_encodable_for_uint!(u8, 8); -impl_encodable_for_uint!(u16, 16); -impl_encodable_for_uint!(u32, 32); -impl_encodable_for_uint!(u64, 64); -impl_encodable_for_uint!(usize, 64); - -impl_encodable_for_u8_array!(4); - -impl Encodable for bool { - fn ssz_append(&self, s: &mut SszStream) { - let byte = if *self { 0b0000_0001 } else { 0b0000_0000 }; - s.append_encoded_raw(&[byte]); - } -} - -impl Encodable for H256 { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(self.as_bytes()); - } -} - -impl Encodable for Address { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(self.as_bytes()); - } -} - -impl Encodable for Vec -where - T: Encodable, -{ - fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::ssz_encode; - - #[test] - fn test_ssz_encode_h256() { - let h = H256::zero(); - let mut ssz = SszStream::new(); - ssz.append(&h); - assert_eq!(ssz.drain(), vec![0; 32]); - } - - #[test] - fn test_ssz_encode_address() { - let h = Address::zero(); - let mut ssz = SszStream::new(); - ssz.append(&h); - assert_eq!(ssz.drain(), vec![0; 20]); - } - - #[test] - fn test_ssz_encode_u8() { - let x: u8 = 0; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0]); - - let x: u8 = 1; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![1]); - - let x: u8 = 100; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![100]); - - let x: u8 = 255; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![255]); - } - - #[test] - fn test_ssz_encode_u16() { - let x: u16 = 1; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0]); - - let x: u16 = 100; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![100, 0]); - - let x: u16 = 1 << 8; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 1]); - - let x: u16 = 65535; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![255, 255]); - } - - #[test] - fn test_ssz_encode_u32() { - let x: u32 = 1; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0, 0, 0]); - - let x: u32 = 100; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![100, 0, 0, 0]); - - let x: u32 = 1 << 16; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 0]); - - let x: u32 = 1 << 24; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 1]); - - let x: u32 = !0; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![255, 255, 255, 255]); - } - - #[test] - fn test_ssz_encode_u64() { - let x: u64 = 1; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]); - - let x: u64 = 100; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]); - - let x: u64 = 1 << 32; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]); - - let x: u64 = !0; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); - } - - #[test] - fn test_ssz_encode_usize() { - let x: usize = 1; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]); - - let x: usize = 100; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]); - - let x: usize = 1 << 32; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]); - - let x: usize = !0; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); - } - - #[test] - fn test_ssz_mixed() { - let mut stream = SszStream::new(); - - let h = Address::zero(); - let a: u8 = 100; - let b: u16 = 65535; - let c: u32 = 1 << 24; - - stream.append(&h); - stream.append(&a); - stream.append(&b); - stream.append(&c); - - let ssz = stream.drain(); - assert_eq!(ssz[0..20], *vec![0; 20]); - assert_eq!(ssz[20], 100); - assert_eq!(ssz[21..23], *vec![255, 255]); - assert_eq!(ssz[23..27], *vec![0, 0, 0, 1]); - } - - #[test] - fn test_ssz_encode_bool() { - let x: bool = false; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0b0000_0000]); - - let x: bool = true; - let mut ssz = SszStream::new(); - ssz.append(&x); - assert_eq!(ssz.drain(), vec![0b0000_0001]); - } - - #[test] - fn test_ssz_encode_u8_array() { - let x: [u8; 4] = [0, 1, 7, 8]; - let ssz = ssz_encode(&x); - assert_eq!(ssz, vec![0, 1, 7, 8]); - - let x: [u8; 4] = [255, 255, 255, 255]; - let ssz = ssz_encode(&x); - assert_eq!(ssz, vec![255, 255, 255, 255]); - } -} diff --git a/eth2/utils/ssz/src/impl_tree_hash.rs b/eth2/utils/ssz/src/impl_tree_hash.rs deleted file mode 100644 index 03976f637..000000000 --- a/eth2/utils/ssz/src/impl_tree_hash.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::ethereum_types::{Address, H256}; -use super::{merkle_hash, ssz_encode, TreeHash}; -use hashing::hash; - -impl TreeHash for u8 { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for u16 { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for u32 { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for u64 { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for usize { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for bool { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for Address { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for H256 { - fn hash_tree_root(&self) -> Vec { - ssz_encode(self) - } -} - -impl TreeHash for [u8] { - fn hash_tree_root(&self) -> Vec { - if self.len() > 32 { - return hash(&self); - } - self.to_vec() - } -} - -impl TreeHash for Vec -where - T: TreeHash, -{ - /// Returns the merkle_hash of a list of hash_tree_root values created - /// from the given list. - /// Note: A byte vector, Vec, must be converted to a slice (as_slice()) - /// to be handled properly (i.e. hashed) as byte array. - fn hash_tree_root(&self) -> Vec { - let mut tree_hashes = self.iter().map(|x| x.hash_tree_root()).collect(); - merkle_hash(&mut tree_hashes) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_impl_tree_hash_vec() { - let result = vec![1u32, 2, 3, 4, 5, 6, 7].hash_tree_root(); - assert_eq!(result.len(), 32); - } -} diff --git a/eth2/utils/ssz/src/lib.rs b/eth2/utils/ssz/src/lib.rs index cb3f63c48..fceebcc44 100644 --- a/eth2/utils/ssz/src/lib.rs +++ b/eth2/utils/ssz/src/lib.rs @@ -1,230 +1,59 @@ -/* - * This is a WIP of implementing an alternative - * serialization strategy. It attempts to follow Vitalik's - * "simpleserialize" format here: - * https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/simpleserialize.py - * - * This implementation is not final and would almost certainly - * have issues. - */ -extern crate bytes; -extern crate ethereum_types; +//! Provides encoding (serialization) and decoding (deserialization) in the SimpleSerialize (SSZ) +//! format designed for use in Ethereum 2.0. +//! +//! Conforms to +//! [v0.6.1](https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/simple-serialize.md) of the +//! Ethereum 2.0 specification. +//! +//! ## Example +//! +//! ```rust +//! use ssz_derive::{Encode, Decode}; +//! use ssz::{Decode, Encode}; +//! +//! #[derive(PartialEq, Debug, Encode, Decode)] +//! struct Foo { +//! a: u64, +//! b: Vec, +//! } +//! +//! fn main() { +//! let foo = Foo { +//! a: 42, +//! b: vec![1, 3, 3, 7] +//! }; +//! +//! let ssz_bytes: Vec = foo.as_ssz_bytes(); +//! +//! let decoded_foo = Foo::from_ssz_bytes(&ssz_bytes).unwrap(); +//! +//! assert_eq!(foo, decoded_foo); +//! } +//! +//! ``` +//! +//! See `examples/` for manual implementations of the `Encode` and `Decode` traits. -pub mod decode; -pub mod encode; -mod signed_root; -pub mod tree_hash; +mod decode; +mod encode; +mod macros; -mod impl_decode; -mod impl_encode; -mod impl_tree_hash; +pub use decode::{ + impls::decode_list_of_variable_length_items, Decode, DecodeError, SszDecoder, SszDecoderBuilder, +}; +pub use encode::{Encode, SszEncoder}; -pub use crate::decode::{decode, decode_ssz_list, Decodable, DecodeError}; -pub use crate::encode::{Encodable, SszStream}; -pub use crate::signed_root::SignedRoot; -pub use crate::tree_hash::{merkle_hash, TreeHash}; - -pub use hashing::hash; - -pub const LENGTH_BYTES: usize = 4; -pub const MAX_LIST_SIZE: usize = 1 << (4 * 8); +/// The number of bytes used to represent an offset. +pub const BYTES_PER_LENGTH_OFFSET: usize = 4; +/// The maximum value that can be represented using `BYTES_PER_LENGTH_OFFSET`. +pub const MAX_LENGTH_VALUE: usize = (1 << (BYTES_PER_LENGTH_OFFSET * 8)) - 1; /// Convenience function to SSZ encode an object supporting ssz::Encode. +/// +/// Equivalent to `val.as_ssz_bytes()`. pub fn ssz_encode(val: &T) -> Vec where - T: Encodable, + T: Encode, { - let mut ssz_stream = SszStream::new(); - ssz_stream.append(val); - ssz_stream.drain() -} - -#[cfg(test)] -mod tests { - extern crate hex; - extern crate yaml_rust; - - use self::yaml_rust::yaml; - use super::*; - use std::{fs::File, io::prelude::*, path::PathBuf}; - - #[test] - pub fn test_vector_uint_bounds() { - let mut file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("src/test_vectors/uint_bounds.yaml"); - - File::open(file_path_buf).unwrap() - }; - let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); - let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); - let doc = &docs[0]; - - // Load test cases - let test_cases = doc["test_cases"].clone(); - - for test_case in test_cases { - // Only the valid cases are checked as parse::() will fail for all invalid cases - if test_case["valid"].as_bool().unwrap() { - // Convert test vector 'ssz' encoded yaml to Vec - let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); - let test_vector_bytes = hex::decode(ssz).unwrap(); - - // Convert test vector 'value' to ssz encoded bytes - let mut bytes: Vec; - match test_case["type"].as_str().unwrap() { - "uint8" => { - let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); // check encoding - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint16" => { - let value: u16 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint32" => { - let value: u32 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint64" => { - let value: u64 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - _ => continue, - }; - assert_eq!(test_vector_bytes, bytes); - } - } - } - - #[test] - pub fn test_vector_uint_random() { - let mut file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("src/test_vectors/uint_random.yaml"); - - File::open(file_path_buf).unwrap() - }; - let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); - let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); - let doc = &docs[0]; - - // Load test cases - let test_cases = doc["test_cases"].clone(); - - for test_case in test_cases { - // Only the valid cases are checked as parse::() will fail for all invalid cases - if test_case["valid"].as_bool().unwrap() { - // Convert test vector 'ssz' encoded yaml to Vec - let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); - let test_vector_bytes = hex::decode(ssz).unwrap(); - - // Convert test vector 'value' to ssz encoded bytes - let mut bytes: Vec; - match test_case["type"].as_str().unwrap() { - "uint8" => { - let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); // check encoding - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint16" => { - let value: u16 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint32" => { - let value: u32 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - "uint64" => { - let value: u64 = - test_case["value"].as_str().unwrap().parse::().unwrap(); - bytes = ssz_encode::(&value); - - // Check decoding - let decoded = decode::(&test_vector_bytes).unwrap(); - assert_eq!(decoded, value); - } - _ => continue, - }; - assert_eq!(test_vector_bytes, bytes); - } - } - } - - #[test] - pub fn test_vector_uint_wrong_length() { - let mut file = { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("src/test_vectors/uint_wrong_length.yaml"); - - File::open(file_path_buf).unwrap() - }; - let mut yaml_str = String::new(); - file.read_to_string(&mut yaml_str).unwrap(); - let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); - let doc = &docs[0]; - - // Load test cases - let test_cases = doc["test_cases"].clone(); - - for test_case in test_cases { - // Convert test vector 'ssz' encoded yaml to Vec - let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); - let test_vector_bytes = hex::decode(ssz).unwrap(); - - // Attempt to decode invalid ssz bytes - match test_case["type"].as_str().unwrap() { - "uint8" => { - let decoded = decode::(&test_vector_bytes); - assert!(decoded.is_err()); - } - "uint16" => { - let decoded = decode::(&test_vector_bytes); - assert!(decoded.is_err()); - } - "uint32" => { - let decoded = decode::(&test_vector_bytes); - assert!(decoded.is_err()); - } - "uint64" => { - let decoded = decode::(&test_vector_bytes); - assert!(decoded.is_err()); - } - _ => continue, - }; - } - } + val.as_ssz_bytes() } diff --git a/eth2/utils/ssz/src/macros.rs b/eth2/utils/ssz/src/macros.rs new file mode 100644 index 000000000..ed50ffd04 --- /dev/null +++ b/eth2/utils/ssz/src/macros.rs @@ -0,0 +1,96 @@ +/// Implements `Encode` for `$impl_type` using an implementation of `From<$impl_type> for +/// $from_type`. +/// +/// In effect, this allows for easy implementation of `Encode` for some type that implements a +/// `From` conversion into another type that already has `Encode` implemented. +#[macro_export] +macro_rules! impl_encode_via_from { + ($impl_type: ty, $from_type: ty) => { + impl ssz::Encode for $impl_type { + fn is_ssz_fixed_len() -> bool { + <$from_type as ssz::Encode>::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + <$from_type as ssz::Encode>::ssz_fixed_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + let conv: $from_type = self.clone().into(); + + conv.ssz_append(buf) + } + } + }; +} + +/// Implements `Decode` for `$impl_type` using an implementation of `From<$impl_type> for +/// $from_type`. +/// +/// In effect, this allows for easy implementation of `Decode` for some type that implements a +/// `From` conversion into another type that already has `Decode` implemented. +#[macro_export] +macro_rules! impl_decode_via_from { + ($impl_type: ty, $from_type: tt) => { + impl ssz::Decode for $impl_type { + fn is_ssz_fixed_len() -> bool { + <$from_type as ssz::Decode>::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + <$from_type as ssz::Decode>::ssz_fixed_len() + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + $from_type::from_ssz_bytes(bytes).and_then(|dec| Ok(dec.into())) + } + } + }; +} + +#[cfg(test)] +mod tests { + use crate as ssz; + use ssz::{Decode, Encode}; + + #[derive(PartialEq, Debug, Clone, Copy)] + struct Wrapper(u64); + + impl From for Wrapper { + fn from(x: u64) -> Wrapper { + Wrapper(x) + } + } + + impl From for u64 { + fn from(x: Wrapper) -> u64 { + x.0 + } + } + + impl_encode_via_from!(Wrapper, u64); + impl_decode_via_from!(Wrapper, u64); + + #[test] + fn impl_encode_via_from() { + let check_encode = |a: u64, b: Wrapper| assert_eq!(a.as_ssz_bytes(), b.as_ssz_bytes()); + + check_encode(0, Wrapper(0)); + check_encode(1, Wrapper(1)); + check_encode(42, Wrapper(42)); + } + + #[test] + fn impl_decode_via_from() { + let check_decode = |bytes: Vec| { + let a = u64::from_ssz_bytes(&bytes).unwrap(); + let b = Wrapper::from_ssz_bytes(&bytes).unwrap(); + + assert_eq!(a, b.into()) + }; + + check_decode(vec![0, 0, 0, 0, 0, 0, 0, 0]); + check_decode(vec![1, 0, 0, 0, 0, 0, 0, 0]); + check_decode(vec![1, 0, 0, 0, 2, 0, 0, 0]); + } +} diff --git a/eth2/utils/ssz/src/signed_root.rs b/eth2/utils/ssz/src/signed_root.rs deleted file mode 100644 index f7aeca4af..000000000 --- a/eth2/utils/ssz/src/signed_root.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::TreeHash; - -pub trait SignedRoot: TreeHash { - fn signed_root(&self) -> Vec; -} diff --git a/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml b/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml deleted file mode 100644 index 4d01e2658..000000000 --- a/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml +++ /dev/null @@ -1,1924 +0,0 @@ -title: UInt Bounds -summary: Integers right at or beyond the bounds of the allowed value range -fork: phase0-0.2.0 -test_cases: -- type: uint8 - valid: true - value: '0' - ssz: '0x00' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint8 - valid: true - value: '255' - ssz: '0xff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint16 - valid: true - value: '0' - ssz: '0x0000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint16 - valid: true - value: '65535' - ssz: '0xffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint24 - valid: true - value: '0' - ssz: '0x000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint24 - valid: true - value: '16777215' - ssz: '0xffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint32 - valid: true - value: '0' - ssz: '0x00000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint32 - valid: true - value: '4294967295' - ssz: '0xffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint40 - valid: true - value: '0' - ssz: '0x0000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint40 - valid: true - value: '1099511627775' - ssz: '0xffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint48 - valid: true - value: '0' - ssz: '0x000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint48 - valid: true - value: '281474976710655' - ssz: '0xffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint56 - valid: true - value: '0' - ssz: '0x00000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint56 - valid: true - value: '72057594037927935' - ssz: '0xffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint64 - valid: true - value: '0' - ssz: '0x0000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint64 - valid: true - value: '18446744073709551615' - ssz: '0xffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint72 - valid: true - value: '0' - ssz: '0x000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint72 - valid: true - value: '4722366482869645213695' - ssz: '0xffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint80 - valid: true - value: '0' - ssz: '0x00000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint80 - valid: true - value: '1208925819614629174706175' - ssz: '0xffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint88 - valid: true - value: '0' - ssz: '0x0000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint88 - valid: true - value: '309485009821345068724781055' - ssz: '0xffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint96 - valid: true - value: '0' - ssz: '0x000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint96 - valid: true - value: '79228162514264337593543950335' - ssz: '0xffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint104 - valid: true - value: '0' - ssz: '0x00000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint104 - valid: true - value: '20282409603651670423947251286015' - ssz: '0xffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint112 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint112 - valid: true - value: '5192296858534827628530496329220095' - ssz: '0xffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint120 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint120 - valid: true - value: '1329227995784915872903807060280344575' - ssz: '0xffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint128 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint128 - valid: true - value: '340282366920938463463374607431768211455' - ssz: '0xffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint136 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint136 - valid: true - value: '87112285931760246646623899502532662132735' - ssz: '0xffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint144 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint144 - valid: true - value: '22300745198530623141535718272648361505980415' - ssz: '0xffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint152 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint152 - valid: true - value: '5708990770823839524233143877797980545530986495' - ssz: '0xffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint160 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint160 - valid: true - value: '1461501637330902918203684832716283019655932542975' - ssz: '0xffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint168 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint168 - valid: true - value: '374144419156711147060143317175368453031918731001855' - ssz: '0xffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint176 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint176 - valid: true - value: '95780971304118053647396689196894323976171195136475135' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint184 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint184 - valid: true - value: '24519928653854221733733552434404946937899825954937634815' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint192 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint192 - valid: true - value: '6277101735386680763835789423207666416102355444464034512895' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint200 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint200 - valid: true - value: '1606938044258990275541962092341162602522202993782792835301375' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint208 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint208 - valid: true - value: '411376139330301510538742295639337626245683966408394965837152255' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint216 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint216 - valid: true - value: '105312291668557186697918027683670432318895095400549111254310977535' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint224 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint224 - valid: true - value: '26959946667150639794667015087019630673637144422540572481103610249215' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint232 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint232 - valid: true - value: '6901746346790563787434755862277025452451108972170386555162524223799295' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint240 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint240 - valid: true - value: '1766847064778384329583297500742918515827483896875618958121606201292619775' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint248 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint248 - valid: true - value: '452312848583266388373324160190187140051835877600158453279131187530910662655' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint256 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint256 - valid: true - value: '115792089237316195423570985008687907853269984665640564039457584007913129639935' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint264 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint264 - valid: true - value: '29642774844752946028434172162224104410437116074403984394101141506025761187823615' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint272 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint272 - valid: true - value: '7588550360256754183279148073529370729071901715047420004889892225542594864082845695' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint280 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint280 - valid: true - value: '1942668892225729070919461906823518906642406839052139521251812409738904285205208498175' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint288 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint288 - valid: true - value: '497323236409786642155382248146820840100456150797347717440463976893159497012533375533055' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint296 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint296 - valid: true - value: '127314748520905380391777855525586135065716774604121015664758778084648831235208544136462335' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint304 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint304 - valid: true - value: '32592575621351777380295131014550050576823494298654980010178247189670100796213387298934358015' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint312 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint312 - valid: true - value: '8343699359066055009355553539724812947666814540455674882605631280555545803830627148527195652095' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint320 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint320 - valid: true - value: '2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint328 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint328 - valid: true - value: '546812681195752981093125556779405341338292357723303109106442651602488249799843980805878294255763455' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint336 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint336 - valid: true - value: '139984046386112763159840142535527767382602843577165595931249318810236991948760059086304843329475444735' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint344 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint344 - valid: true - value: '35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852415' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint352 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint352 - valid: true - value: '9173994463960286046443283581208347763186259956673124494950355357547691504353939232280074212440502746218495' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint360 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint360 - valid: true - value: '2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934975' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint368 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint368 - valid: true - value: '601226901190101306339707032778070279008174732520529886901066488712245510429339761526706943586500787976175353855' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint376 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint376 - valid: true - value: '153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890587135' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint384 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint384 - valid: true - value: '39402006196394479212279040100143613805079739270465446667948293404245721771497210611414266254884915640806627990306815' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint392 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint392 - valid: true - value: '10086913586276986678343434265636765134100413253239154346994763111486904773503285916522052161250538404046496765518544895' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint400 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint400 - valid: true - value: '2582249878086908589655919172003011874329705792829223512830659356540647622016841194629645353280137831435903171972747493375' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint408 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint408 - valid: true - value: '661055968790248598951915308032771039828404682964281219284648795274405791236311345825189210439715284847591212025023358304255' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint416 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint416 - valid: true - value: '169230328010303641331690318856389386196071598838855992136870091590247882556495704531248437872567112920983350278405979725889535' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint424 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint424 - valid: true - value: '43322963970637732180912721627235682866194329302747133987038743447103457934462900359999600095377180907771737671271930809827721215' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint432 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint432 - valid: true - value: '11090678776483259438313656736572334813745748301503266300681918322458485231222502492159897624416558312389564843845614287315896631295' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint440 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint440 - valid: true - value: '2839213766779714416208296124562517712318911565184836172974571090549372219192960637992933791850638927971728600024477257552869537611775' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint448 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint448 - valid: true - value: '726838724295606890549323807888004534353641360687318060281490199180639288113397923326191050713763565560762521606266177933534601628614655' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint456 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint456 - valid: true - value: '186070713419675363980626894819329160794532188335953423432061490990243657757029868371504908982723472783555205531204141550984858016925351935' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint464 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint464 - valid: true - value: '47634102635436893179040485073748265163400240214004076398607741693502376385799646303105256699577209032590132615988260237052123652332890095615' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint472 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint472 - valid: true - value: '12194330274671844653834364178879555881830461494785043558043581873536608354764709453594945715091765512343073949692994620685343654997219864477695' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint480 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint480 - valid: true - value: '3121748550315992231381597229793166305748598142664971150859156959625371738819765620120306103063491971159826931121406622895447975679288285306290175' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint488 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint488 - valid: true - value: '799167628880894011233688890827050574271641124522232614619944181664095165137859998750798362384253944616915694367080095461234681773897801038410285055' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint496 - valid: true - value: '0' - ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint496 - valid: true - value: '204586912993508866875824356051724947013540127877691549342705710506008362275292159680204380770369009821930417757972504438076078534117837065833032974335' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint504 - valid: true - value: '0' - ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint504 - valid: true - value: '52374249726338269920211035149241586435466272736689036631732661889538140742474792878132321477214466514414186946040961136147476104734166288853256441430015' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint512 - valid: true - value: '0' - ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - tags: - - atomic - - uint - - uint_lower_bound -- type: uint512 - valid: true - value: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095' - ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - tags: - - atomic - - uint - - uint_upper_bound -- type: uint8 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint8 - valid: false - value: '256' - tags: - - atomic - - uint - - uint_overflow -- type: uint16 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint16 - valid: false - value: '65536' - tags: - - atomic - - uint - - uint_overflow -- type: uint24 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint24 - valid: false - value: '16777216' - tags: - - atomic - - uint - - uint_overflow -- type: uint32 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint32 - valid: false - value: '4294967296' - tags: - - atomic - - uint - - uint_overflow -- type: uint40 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint40 - valid: false - value: '1099511627776' - tags: - - atomic - - uint - - uint_overflow -- type: uint48 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint48 - valid: false - value: '281474976710656' - tags: - - atomic - - uint - - uint_overflow -- type: uint56 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint56 - valid: false - value: '72057594037927936' - tags: - - atomic - - uint - - uint_overflow -- type: uint64 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint64 - valid: false - value: '18446744073709551616' - tags: - - atomic - - uint - - uint_overflow -- type: uint72 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint72 - valid: false - value: '4722366482869645213696' - tags: - - atomic - - uint - - uint_overflow -- type: uint80 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint80 - valid: false - value: '1208925819614629174706176' - tags: - - atomic - - uint - - uint_overflow -- type: uint88 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint88 - valid: false - value: '309485009821345068724781056' - tags: - - atomic - - uint - - uint_overflow -- type: uint96 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint96 - valid: false - value: '79228162514264337593543950336' - tags: - - atomic - - uint - - uint_overflow -- type: uint104 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint104 - valid: false - value: '20282409603651670423947251286016' - tags: - - atomic - - uint - - uint_overflow -- type: uint112 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint112 - valid: false - value: '5192296858534827628530496329220096' - tags: - - atomic - - uint - - uint_overflow -- type: uint120 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint120 - valid: false - value: '1329227995784915872903807060280344576' - tags: - - atomic - - uint - - uint_overflow -- type: uint128 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint128 - valid: false - value: '340282366920938463463374607431768211456' - tags: - - atomic - - uint - - uint_overflow -- type: uint136 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint136 - valid: false - value: '87112285931760246646623899502532662132736' - tags: - - atomic - - uint - - uint_overflow -- type: uint144 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint144 - valid: false - value: '22300745198530623141535718272648361505980416' - tags: - - atomic - - uint - - uint_overflow -- type: uint152 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint152 - valid: false - value: '5708990770823839524233143877797980545530986496' - tags: - - atomic - - uint - - uint_overflow -- type: uint160 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint160 - valid: false - value: '1461501637330902918203684832716283019655932542976' - tags: - - atomic - - uint - - uint_overflow -- type: uint168 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint168 - valid: false - value: '374144419156711147060143317175368453031918731001856' - tags: - - atomic - - uint - - uint_overflow -- type: uint176 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint176 - valid: false - value: '95780971304118053647396689196894323976171195136475136' - tags: - - atomic - - uint - - uint_overflow -- type: uint184 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint184 - valid: false - value: '24519928653854221733733552434404946937899825954937634816' - tags: - - atomic - - uint - - uint_overflow -- type: uint192 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint192 - valid: false - value: '6277101735386680763835789423207666416102355444464034512896' - tags: - - atomic - - uint - - uint_overflow -- type: uint200 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint200 - valid: false - value: '1606938044258990275541962092341162602522202993782792835301376' - tags: - - atomic - - uint - - uint_overflow -- type: uint208 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint208 - valid: false - value: '411376139330301510538742295639337626245683966408394965837152256' - tags: - - atomic - - uint - - uint_overflow -- type: uint216 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint216 - valid: false - value: '105312291668557186697918027683670432318895095400549111254310977536' - tags: - - atomic - - uint - - uint_overflow -- type: uint224 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint224 - valid: false - value: '26959946667150639794667015087019630673637144422540572481103610249216' - tags: - - atomic - - uint - - uint_overflow -- type: uint232 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint232 - valid: false - value: '6901746346790563787434755862277025452451108972170386555162524223799296' - tags: - - atomic - - uint - - uint_overflow -- type: uint240 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint240 - valid: false - value: '1766847064778384329583297500742918515827483896875618958121606201292619776' - tags: - - atomic - - uint - - uint_overflow -- type: uint248 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint248 - valid: false - value: '452312848583266388373324160190187140051835877600158453279131187530910662656' - tags: - - atomic - - uint - - uint_overflow -- type: uint256 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint256 - valid: false - value: '115792089237316195423570985008687907853269984665640564039457584007913129639936' - tags: - - atomic - - uint - - uint_overflow -- type: uint264 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint264 - valid: false - value: '29642774844752946028434172162224104410437116074403984394101141506025761187823616' - tags: - - atomic - - uint - - uint_overflow -- type: uint272 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint272 - valid: false - value: '7588550360256754183279148073529370729071901715047420004889892225542594864082845696' - tags: - - atomic - - uint - - uint_overflow -- type: uint280 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint280 - valid: false - value: '1942668892225729070919461906823518906642406839052139521251812409738904285205208498176' - tags: - - atomic - - uint - - uint_overflow -- type: uint288 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint288 - valid: false - value: '497323236409786642155382248146820840100456150797347717440463976893159497012533375533056' - tags: - - atomic - - uint - - uint_overflow -- type: uint296 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint296 - valid: false - value: '127314748520905380391777855525586135065716774604121015664758778084648831235208544136462336' - tags: - - atomic - - uint - - uint_overflow -- type: uint304 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint304 - valid: false - value: '32592575621351777380295131014550050576823494298654980010178247189670100796213387298934358016' - tags: - - atomic - - uint - - uint_overflow -- type: uint312 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint312 - valid: false - value: '8343699359066055009355553539724812947666814540455674882605631280555545803830627148527195652096' - tags: - - atomic - - uint - - uint_overflow -- type: uint320 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint320 - valid: false - value: '2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576' - tags: - - atomic - - uint - - uint_overflow -- type: uint328 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint328 - valid: false - value: '546812681195752981093125556779405341338292357723303109106442651602488249799843980805878294255763456' - tags: - - atomic - - uint - - uint_overflow -- type: uint336 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint336 - valid: false - value: '139984046386112763159840142535527767382602843577165595931249318810236991948760059086304843329475444736' - tags: - - atomic - - uint - - uint_overflow -- type: uint344 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint344 - valid: false - value: '35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852416' - tags: - - atomic - - uint - - uint_overflow -- type: uint352 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint352 - valid: false - value: '9173994463960286046443283581208347763186259956673124494950355357547691504353939232280074212440502746218496' - tags: - - atomic - - uint - - uint_overflow -- type: uint360 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint360 - valid: false - value: '2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934976' - tags: - - atomic - - uint - - uint_overflow -- type: uint368 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint368 - valid: false - value: '601226901190101306339707032778070279008174732520529886901066488712245510429339761526706943586500787976175353856' - tags: - - atomic - - uint - - uint_overflow -- type: uint376 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint376 - valid: false - value: '153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890587136' - tags: - - atomic - - uint - - uint_overflow -- type: uint384 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint384 - valid: false - value: '39402006196394479212279040100143613805079739270465446667948293404245721771497210611414266254884915640806627990306816' - tags: - - atomic - - uint - - uint_overflow -- type: uint392 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint392 - valid: false - value: '10086913586276986678343434265636765134100413253239154346994763111486904773503285916522052161250538404046496765518544896' - tags: - - atomic - - uint - - uint_overflow -- type: uint400 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint400 - valid: false - value: '2582249878086908589655919172003011874329705792829223512830659356540647622016841194629645353280137831435903171972747493376' - tags: - - atomic - - uint - - uint_overflow -- type: uint408 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint408 - valid: false - value: '661055968790248598951915308032771039828404682964281219284648795274405791236311345825189210439715284847591212025023358304256' - tags: - - atomic - - uint - - uint_overflow -- type: uint416 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint416 - valid: false - value: '169230328010303641331690318856389386196071598838855992136870091590247882556495704531248437872567112920983350278405979725889536' - tags: - - atomic - - uint - - uint_overflow -- type: uint424 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint424 - valid: false - value: '43322963970637732180912721627235682866194329302747133987038743447103457934462900359999600095377180907771737671271930809827721216' - tags: - - atomic - - uint - - uint_overflow -- type: uint432 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint432 - valid: false - value: '11090678776483259438313656736572334813745748301503266300681918322458485231222502492159897624416558312389564843845614287315896631296' - tags: - - atomic - - uint - - uint_overflow -- type: uint440 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint440 - valid: false - value: '2839213766779714416208296124562517712318911565184836172974571090549372219192960637992933791850638927971728600024477257552869537611776' - tags: - - atomic - - uint - - uint_overflow -- type: uint448 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint448 - valid: false - value: '726838724295606890549323807888004534353641360687318060281490199180639288113397923326191050713763565560762521606266177933534601628614656' - tags: - - atomic - - uint - - uint_overflow -- type: uint456 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint456 - valid: false - value: '186070713419675363980626894819329160794532188335953423432061490990243657757029868371504908982723472783555205531204141550984858016925351936' - tags: - - atomic - - uint - - uint_overflow -- type: uint464 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint464 - valid: false - value: '47634102635436893179040485073748265163400240214004076398607741693502376385799646303105256699577209032590132615988260237052123652332890095616' - tags: - - atomic - - uint - - uint_overflow -- type: uint472 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint472 - valid: false - value: '12194330274671844653834364178879555881830461494785043558043581873536608354764709453594945715091765512343073949692994620685343654997219864477696' - tags: - - atomic - - uint - - uint_overflow -- type: uint480 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint480 - valid: false - value: '3121748550315992231381597229793166305748598142664971150859156959625371738819765620120306103063491971159826931121406622895447975679288285306290176' - tags: - - atomic - - uint - - uint_overflow -- type: uint488 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint488 - valid: false - value: '799167628880894011233688890827050574271641124522232614619944181664095165137859998750798362384253944616915694367080095461234681773897801038410285056' - tags: - - atomic - - uint - - uint_overflow -- type: uint496 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint496 - valid: false - value: '204586912993508866875824356051724947013540127877691549342705710506008362275292159680204380770369009821930417757972504438076078534117837065833032974336' - tags: - - atomic - - uint - - uint_overflow -- type: uint504 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint504 - valid: false - value: '52374249726338269920211035149241586435466272736689036631732661889538140742474792878132321477214466514414186946040961136147476104734166288853256441430016' - tags: - - atomic - - uint - - uint_overflow -- type: uint512 - valid: false - value: '-1' - tags: - - atomic - - uint - - uint_underflow -- type: uint512 - valid: false - value: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096' - tags: - - atomic - - uint - - uint_overflow diff --git a/eth2/utils/ssz/src/test_vectors/uint_random.yaml b/eth2/utils/ssz/src/test_vectors/uint_random.yaml deleted file mode 100644 index b473eed7e..000000000 --- a/eth2/utils/ssz/src/test_vectors/uint_random.yaml +++ /dev/null @@ -1,5124 +0,0 @@ -title: UInt Random -summary: Random integers chosen uniformly over the allowed value range -fork: phase0-0.2.0 -test_cases: -- type: uint8 - valid: true - value: '197' - ssz: '0xc5' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '215' - ssz: '0xd7' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '20' - ssz: '0x14' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '132' - ssz: '0x84' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '248' - ssz: '0xf8' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '207' - ssz: '0xcf' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '155' - ssz: '0x9b' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '244' - ssz: '0xf4' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '183' - ssz: '0xb7' - tags: - - atomic - - uint - - random -- type: uint8 - valid: true - value: '111' - ssz: '0x6f' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '18254' - ssz: '0x4e47' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '36941' - ssz: '0x4d90' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '18316' - ssz: '0x8c47' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '12429' - ssz: '0x8d30' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '32834' - ssz: '0x4280' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '19262' - ssz: '0x3e4b' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '40651' - ssz: '0xcb9e' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '12945' - ssz: '0x9132' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '9665' - ssz: '0xc125' - tags: - - atomic - - uint - - random -- type: uint16 - valid: true - value: '43279' - ssz: '0x0fa9' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '15842480' - ssz: '0xb0bcf1' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '3378971' - ssz: '0x1b8f33' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '11871267' - ssz: '0x2324b5' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '14568389' - ssz: '0xc54bde' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '10609800' - ssz: '0x88e4a1' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '6861134' - ssz: '0x4eb168' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '16005792' - ssz: '0xa03af4' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '14854324' - ssz: '0xb4a8e2' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '8740671' - ssz: '0x3f5f85' - tags: - - atomic - - uint - - random -- type: uint24 - valid: true - value: '2089756' - ssz: '0x1ce31f' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '60308648' - ssz: '0xa83c9803' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '3726325546' - ssz: '0x2a371bde' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '3738645480' - ssz: '0xe833d7de' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '2437440079' - ssz: '0x4f624891' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '4155553746' - ssz: '0xd2b7b0f7' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '1924014660' - ssz: '0x4422ae72' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '4006490763' - ssz: '0x8b32ceee' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '468399889' - ssz: '0x1137eb1b' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '2367674807' - ssz: '0xb7d91f8d' - tags: - - atomic - - uint - - random -- type: uint32 - valid: true - value: '3034658173' - ssz: '0x7d35e1b4' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '732495681130' - ssz: '0x6a16258caa' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '448997099201' - ssz: '0xc106508a68' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '633883988599' - ssz: '0x77126e9693' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '199479708933' - ssz: '0x05cdea712e' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '697437839781' - ssz: '0xa5e18862a2' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '530753379698' - ssz: '0x72dd5d937b' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '404973881548' - ssz: '0xcc08534a5e' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '69521473973' - ssz: '0xb581cd2f10' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '574050980983' - ssz: '0x77d41aa885' - tags: - - atomic - - uint - - random -- type: uint40 - valid: true - value: '152370540412' - ssz: '0x7ceffd7923' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '73309755692216' - ssz: '0xb854f2c1ac42' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '84189419668971' - ssz: '0xeb0574e0914c' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '21753680278216' - ssz: '0xc8b262ecc813' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '45178084358440' - ssz: '0x2879abd71629' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '132576241444389' - ssz: '0x25e6c6cf9378' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '121147496065427' - ssz: '0x93e977d92e6e' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '236115611339380' - ssz: '0x74ca23f3bed6' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '154930550072434' - ssz: '0x72e46694e88c' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '277340858358401' - ssz: '0x811a58733dfc' - tags: - - atomic - - uint - - random -- type: uint48 - valid: true - value: '201179675449946' - ssz: '0x5a5a17cbf8b6' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '46740132276364656' - ssz: '0x70651615e70da6' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '16623652076214918' - ssz: '0x865adf9c1f0f3b' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '48317568742675975' - ssz: '0x075651a192a8ab' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '27436486644662530' - ssz: '0x020157d8567961' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '2335965036647725' - ssz: '0x2d95373e8c4c08' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '39060686294409394' - ssz: '0xb2e042bb7cc58a' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '53619523721370132' - ssz: '0x141a7038ac7ebe' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '24569015937124920' - ssz: '0x38ca69cb634957' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '61411969267209949' - ssz: '0xdd162155dc2dda' - tags: - - atomic - - uint - - random -- type: uint56 - valid: true - value: '8962878696566339' - ssz: '0x43aedfd0b0d71f' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '14445986723726977549' - ssz: '0x0d6ac11963747ac8' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '12869751746724260959' - ssz: '0x5f6cf6da068b9ab2' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '492468956296214015' - ssz: '0xff75f112e899d506' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '10624456751094728287' - ssz: '0x5f8680d41fa77193' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '1688464693572029653' - ssz: '0xd54c2664b1a16e17' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '18087339706428085269' - ssz: '0x15d476d5a12303fb' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '11169580477999807763' - ssz: '0x13fd50094452029b' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '13246852848846262826' - ssz: '0x2a525a2f7b46d6b7' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '11448048936325307157' - ssz: '0x155bf56cdaa3df9e' - tags: - - atomic - - uint - - random -- type: uint64 - valid: true - value: '4794675689233954666' - ssz: '0x6ab7fdd5221c8a42' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '4120085711648797646463' - ssz: '0x7f5e124d98ddac59df' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '2457094427075785960776' - ssz: '0x48ad2a642efb083385' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '1596930364856374240246' - ssz: '0xf6a321ebef59dc9156' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '1930869412047970125437' - ssz: '0x7d469cb2122c32ac68' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '549110656645481873336' - ssz: '0xb8bf6ff7e7f070c41d' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '1506659991209273252530' - ssz: '0xb2dae4c9608f1bad51' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '3231167738247765671697' - ssz: '0x11bf6dd879d27529af' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '1111429009663473721195' - ssz: '0x6b9f8b87af0b2d403c' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '4185961329941969064453' - ssz: '0x0552c7986813e2ebe2' - tags: - - atomic - - uint - - random -- type: uint72 - valid: true - value: '113905314839449117867' - ssz: '0xab2465aa59f8c02c06' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '991100786258446953247093' - ssz: '0x7571bc780a6968aedfd1' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '753031464925852152864291' - ssz: '0x239e33825e02e2ea759f' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '939683731400428233982275' - ssz: '0x438120a6e74a6e5bfcc6' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '606725543462066682132072' - ssz: '0x68f670d60c8959a87a80' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '679126923996089191416816' - ssz: '0xf0c3b20bca85588bcf8f' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '851621275047832368203991' - ssz: '0xd74800f41b05597b56b4' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '808533679326786790044343' - ssz: '0xb7323b31af50d6b236ab' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '539405659904328750267652' - ssz: '0x04fdfa28515d4a3d3972' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '915520175015944101075823' - ssz: '0x6f9b2ca339ffb872dec1' - tags: - - atomic - - uint - - random -- type: uint80 - valid: true - value: '1001987930223867019288330' - ssz: '0x0a5f729107b3e1df2dd4' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '258869700201785255971724076' - ssz: '0x2c1babb305de4591ca21d6' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '275659642544661352293187823' - ssz: '0xefc0f90bc7ac692a3305e4' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '24084251387950612164675660' - ssz: '0x4c88040060a445e209ec13' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '193154701063539917246494799' - ssz: '0x4ff89c7e570f715319c69f' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '30859991048663997988858871' - ssz: '0xf7eb75d6e53f8677db8619' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '256957625909962351801772015' - ssz: '0xefa763f9dd6cfacfe48cd4' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '9116989420681003923005314' - ssz: '0x82df69213655a0fc988a07' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '2100038518022097336290642' - ssz: '0x524de06a2bfcf050b3bc01' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '117888974214719880278579137' - ssz: '0xc117b09c15650819f68361' - tags: - - atomic - - uint - - random -- type: uint88 - valid: true - value: '187186470036140670279874587' - ssz: '0x1bf8d132edc6a7df46d69a' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '77525960717344515985507152630' - ssz: '0xf6f2ac474a2844b0bff87ffa' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '6444848414695649181034209662' - ssz: '0x7ee18d65c9f4aca0bc0dd314' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '68243962408500728882382955796' - ssz: '0x14e5d6cae2b7a31d271582dc' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '27496372991539443643614608096' - ssz: '0xe0ba99a6f3d41aa57677d858' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '3221676592695309469625698690' - ssz: '0x8249c1041504d40a8ee8680a' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '44237499188219561716965821951' - ssz: '0xffcd55ae4db17942d466f08e' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '50717211258777902825126495010' - ssz: '0x220318e715076b753b4be0a3' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '42619109157011030380406953397' - ssz: '0xb5d5585f12c614df68b3b589' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '46516875161662588211695011193' - ssz: '0x79453535aef0256077db4d96' - tags: - - atomic - - uint - - random -- type: uint96 - valid: true - value: '11965288496913229204009981023' - ssz: '0x5f1447022cea71236574a926' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '14957454944671370317321635250309' - ssz: '0x85405a55172067564dbe24cabc' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '10936750860918651870040282600946' - ssz: '0xf295db9e4f5f2109c7468c0a8a' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '4618479523891140601380094965647' - ssz: '0x8f77698c0c263021bdb81c4b3a' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '12206751363239421091481079160489' - ssz: '0xa99ee685dd8289bae61124129a' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '12147936957240142789556575803353' - ssz: '0xd91736673f3ee7d5fcee195499' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '13664798469962208486423441295381' - ssz: '0x15c89de8821b2e7b695e5879ac' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '4712418733315898860010519235870' - ssz: '0x1e8df95717c0d31f186aa57a3b' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '1539128697874164453438201048396' - ssz: '0x4cad18b393876b7f4a6b316d13' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '6807259070938440085984182231646' - ssz: '0x5e62f7e4239ad92765ba70eb55' - tags: - - atomic - - uint - - random -- type: uint104 - valid: true - value: '3536656322122519847766685699159' - ssz: '0x57cc7cf97aedd2fdfc8a8da32c' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '2056532122597058116990906754828949' - ssz: '0x958ada10e32ecacea1e7ac156565' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '3996114906184243389819322413577166' - ssz: '0xce73f7bff54d973805eea70f06c5' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '868770318498488032272447445583337' - ssz: '0xe9c5e6ada1ed9d3735394c6cd52a' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '1729929268554041758696502326947101' - ssz: '0x1d6dcb425180d1953309f0c64a55' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '1194313726651249716381469936746563' - ssz: '0x4380646efe4e2331ebfdc75be23a' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '2094450107269228229217567740056712' - ssz: '0x88d49c738fcd9fc055b14aad4367' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '2663444668374853380684782301669273' - ssz: '0x99e7701eed1f417f9349e0655183' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '4760360601309573758337428313570544' - ssz: '0xf07c7725ee02c91a202aae32b4ea' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '4395156956879795456217704634614627' - ssz: '0x6383e96701cb6ba3c8db0faeb2d8' - tags: - - atomic - - uint - - random -- type: uint112 - valid: true - value: '100795555709089593156730443394356' - ssz: '0x34ed199c2f8e6aee99830138f804' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '855557341180839216834057590154814467' - ssz: '0x036425e650737951ce3470d13bc6a4' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '414467537111385463109004141787284313' - ssz: '0x5903c3417a1f439afb23bfc8d3d24f' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '782602525170513983755779101977421884' - ssz: '0x3c28a3d78c7a06618e173c9548b996' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '1250621125234440715142519718833256908' - ssz: '0xcc79d7b7ccdfd4b4702e9bce61dcf0' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '176400952363716085393125226801261643' - ssz: '0x4bec6fdeb6245feaf727170a3df921' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '798728503173792473043367850535783055' - ssz: '0x8f8a9f39811068214edc660a5bd499' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '1192554411710388236058091592161540610' - ssz: '0x02bae903d62f47c21c6a0dd878ade5' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '1224843992914725675209602722260650169' - ssz: '0xb90819263fd462de5c19f5a778e5eb' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '1016148444240496496752914943882694271' - ssz: '0x7f0ef6f720f30e5ff4a84781fcb3c3' - tags: - - atomic - - uint - - random -- type: uint120 - valid: true - value: '89372021651947878414619559095819678' - ssz: '0x9eddade68f79a18723299f80613611' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '337060767022057562817716766532192406084' - ssz: '0x448a9b847b3802c2b1eca299dc8a93fd' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '256783291218949627655514667026556198843' - ssz: '0xbb1f39bfd85d266dd83ee1e7b8a92ec1' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '203697878000813760667695904499069054426' - ssz: '0xda6d274af00a1189e206b1e6c6c83e99' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '199537652244744202127932003531962470534' - ssz: '0x8650e4f835407963da86809bcf8d1d96' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '61920815631763823374286214731610985269' - ssz: '0x3513a0e23dc60f00a27da1bdea83952e' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '113207116805824726959666891960218644120' - ssz: '0x986ec18188fefc915b402441cae52a55' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '12227650489491460353732842508880356285' - ssz: '0xbda382552605370ef7df1df1b6f53209' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '120042034974009028372474670245205798503' - ssz: '0x676ec0261c116fcf79c298fc45414f5a' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '131581408829052556530741761927364578030' - ssz: '0xee8a0109f3039d9cc30e5e7754a8fd62' - tags: - - atomic - - uint - - random -- type: uint128 - valid: true - value: '264790163841886451907268300974850726247' - ssz: '0x67590a0c6ea0fa19f6318c7805bb34c7' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '23009009063061163022450380671176753916627' - ssz: '0xd3aa2d0519a84f08a1342a995bf40d9e43' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '21659133330573268078148387705790285168039' - ssz: '0xa73ddfa1731615ef62587e56575885a63f' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '51594305779282661227020278594601848156745' - ssz: '0x493230f8d042baaeb298afb694d83d9f97' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '77377496959774602887967646747014843770993' - ssz: '0x71a86a301774c60945a138c876d75b64e3' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '62086379269917149809161197528013747517820' - ssz: '0x7cf91f5fc499b1c12323c3308cb29974b6' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '7811691319131517516713442356807602308429' - ssz: '0x4d8520ca82a1cba17a744913d505ddf416' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '44402141111700929609393251490894966995167' - ssz: '0xdfb8e4e6389a2def6f2c3c0af250757c82' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '39886530905979994183117025957314844872576' - ssz: '0x80cfba91de466192677e39e0c96c4a3775' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '20058109343621868312836589995732018947826' - ssz: '0xf2668c6b06bfd18174e6284e5d570bf23a' - tags: - - atomic - - uint - - random -- type: uint136 - valid: true - value: '73693595488587541989362153463090657359790' - ssz: '0xaef74b25c3620c6da9c34fe4e139e690d8' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '18537938434671927673504053721942482481178358' - ssz: '0xf6e641ecee1f8315f09f8defaadad11aced4' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '6964822520642714507357766228271899648701946' - ssz: '0xfab51b1035e465194205486a1efc18c6f34f' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '19924482427972148126040520741003541725428481' - ssz: '0x01bbf9bb06a45df4b102dc07e47195cab8e4' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '22150010364133189339955994960634393946467360' - ssz: '0x20ac5b6ec818b9af75cac16a8ee0b60745fe' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '5413576107222835186956044353627325981096127' - ssz: '0xbf78a9401b1a1b1467a33d5aaa1c0112253e' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '15515972633371723766275325375766903444211318' - ssz: '0x7606f85b232d18b1d748850721176f581db2' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '10280602132159287262346798691546599512562497' - ssz: '0x415b8b2d2b048d02f3938cd403446df90376' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '5494505658031558207419599196163684871928498' - ssz: '0xb27a7bac95006bbbb9f431f00ba4a1e6123f' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '21261220812273676537470962117242856729132089' - ssz: '0x39bc522435b0de2f9d7e3c74a0a8c51c11f4' - tags: - - atomic - - uint - - random -- type: uint144 - valid: true - value: '5805305046991641699899793191766891449670002' - ssz: '0x72d92d58d8701db5ce438cf55ea11a42a442' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '3825174099518686858057314999576904383076947018' - ssz: '0x4ad426076ece6df75e5c473580c0bb5cd886ab' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '3733499060455947131415925977452526654235574132' - ssz: '0x747fdfe0222e49f5b9cf9e8d385fcba2776aa7' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '1171261462346026422309786724078180692622416879' - ssz: '0xef9b1d2f701ed097bd1632fe46e6af146c8534' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '4299885285731473134889752519770808655649283906' - ssz: '0x429f81889d8bb294ff85c94eee070a2843d0c0' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '2702147309269105497705921292095138251485646870' - ssz: '0x16900a399242de50451322823ead2a3e212b79' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '4793101510903444695037543558116210027809105583' - ssz: '0xaf663ec150fb162f6ae0824a2caa595f1beed6' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '835923609654474138522615349897791780610555253' - ssz: '0x75bd42055927d0647ca3f213c361c1b3ee7b25' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '4758435986015644358755755548334659359082288307' - ssz: '0xb314cc21094e946baf9aa44cb1bbff8c2a60d5' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '4820543316492109470742949918242820586188979194' - ssz: '0xfa3baabd8d5028ed9cb06c247eca50971f29d8' - tags: - - atomic - - uint - - random -- type: uint152 - valid: true - value: '2832327379109300624533093590716906616384098814' - ssz: '0xfe914b4cdd3410a3c7b6c45a2c71a51586017f' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '298132119759970464683080205048551339723898620303' - ssz: '0x8f096abada20b9e6b77e175299ddf870e4b43834' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '1388818723368950524729130409846395238709059811556' - ssz: '0xe478164b8a9dccf31e168c78547a4f1711c944f3' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '630954366773311866370781714447899061244390686299' - ssz: '0x5b3e1666de1b752f8d1a84c447d0f46beaf8846e' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '931420146329679607955376257103221731696488435095' - ssz: '0x974d7f24785cf95acc296276c017aba1e85226a3' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '11365591825650676268094601246636917941215502073' - ssz: '0xf91ef1b2b174f7726c73659eca57467698a6fd01' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '919168166853120564410328465631358663091658059707' - ssz: '0xbb6f6e4c80114d1dfb36c5c428cd92fa14ed00a1' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '51811646046192928226923063007458662298811723569' - ssz: '0x316fa5e899142f32d5c86c98a98cd31587501309' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '496750394593545954208482528091910002500822893171' - ssz: '0x7302d0ca9d5532432d0f3c4ee28a9c88de0e0357' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '423385258122450374735040807575953166293599697284' - ssz: '0x84b9de29648a6e113353326a7ba266dc6740294a' - tags: - - atomic - - uint - - random -- type: uint160 - valid: true - value: '916565680350180742247901247333093042409086114078' - ssz: '0x1ed9138527626922b878f0925042e785003a8ca0' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '208685155101564224577462553158083992182641352118507' - ssz: '0xeb104667ef29cebdcd114fc7768a6fe7f1fec5c98e' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '103224122787274465835033055754836485431603577826124' - ssz: '0x4c2bd14ab1ce3e7167912e5fd4b6779174c0f9a046' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '300165292943880195108843318150884006362700836093147' - ssz: '0xdbbc3528d578901f55af70b20942da1edd3fa561cd' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '224586411240470228409514685871176383884323804143324' - ssz: '0xdcde4f97271acb77f370b823bece428f53fb12ab99' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '162833361893063202578352237831921852476808090585386' - ssz: '0x2a89a35abc0ed2a1619c0079565a0abe907a446a6f' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '368763521147822607595016382085290626340472866079418' - ssz: '0xba020a7afbce257da092d7b19bb4668032307851fc' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '107128340616938989509014223809605082531706505595584' - ssz: '0xc00aeda65c2e5bf55bb76a0fc6c9a87124efd84c49' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '161672980449300553331129731676348586984229386457086' - ssz: '0xfe0fc6beb99ada7eb0786a0dd36628e3dc2c039f6e' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '86288778115854259107907493184348540461239836611758' - ssz: '0xae1444ab61492665a1f7a40162bc7c5ce4a18a0a3b' - tags: - - atomic - - uint - - random -- type: uint168 - valid: true - value: '105559421341633923494711123458827890612233020808168' - ssz: '0xe89b1eb3f302e34afe3823babaf895e62129083a48' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '83140597773196103858588251276809779941296254527063362' - ssz: '0x42c569c0d751a692fb64b54985c4f230ae71ff1a37de' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '63347572874011887694417969607546203362409158998308151' - ssz: '0x3735fd75496f62b7c3b58754955a56622cc9122b50a9' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '28355229414081083465774610134863696059623243894828541' - ssz: '0xfd2df56b19a7e3a599f6aee55425feaf79df6d6fc94b' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '60547855894773048857039893325660012034511957248817321' - ssz: '0xa9b88172cb4be8ee6ebc75b56a9bc225e1782f86d4a1' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '66887733022528204775294989864333518229333007219868374' - ssz: '0xd6c21421663f7835f8790fe9f2b9d32fe421b271c6b2' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '94240266283512444958584476278055131942156426015803821' - ssz: '0xad0912ca929ec5fb1a528d630ce4626df2758dcee1fb' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '84147705009790231301060331685768170104811846087780503' - ssz: '0x97a8b8636b11d3badc5f5c38515babcb4bd03932e8e0' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '16594784769879697675422886666139924948892303707224771' - ssz: '0xc33a622cf917aa3beb115c9caabd2a4c1f3ecd9c5a2c' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '10333486373838094427217027595952712322826460203126059' - ssz: '0x2b0da1e0491f09e2c4dd625a15a15369e8c652759e1b' - tags: - - atomic - - uint - - random -- type: uint176 - valid: true - value: '82488517565067170439429897131942042173412572010143906' - ssz: '0xa26068f43818148cdebd04ee67ba02bca3a01fef78dc' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '23325929613275145022302073467642372979830015811842067893' - ssz: '0xb5cdb9940dd26074f5e17d7de2703741e0ff40b4b888f3' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '2577206205287141659870094756106145554158587044243553548' - ssz: '0x0cbd2537e05c5256ae301044a4ebcf0acdf3360b44e81a' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '349657915962513626344116028627044050882721725461628963' - ssz: '0x2308b129b4a38c5923ecfd00cdf7304a54ac95a78da603' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '10895013405319269419501563428819292743207913038957098622' - ssz: '0x7eb6f12366ff4d1048d163c908ab806d908235aecebf71' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '10836482078303888725446464507249725189954602256618632544' - ssz: '0x60357ef8c4b1cf9b34f9816598eac98e2c57e0eb5d2371' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '12322591428258660824406870149343649226386367531794732737' - ssz: '0xc1964686bbe382581cae1230b3b158d6f5789d3363a780' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '21489197691014261855472609522952688351555575272215722455' - ssz: '0xd7b984125f7c5b02f093ff750c04cc7ebbb37fb9915be0' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '24205189860902688400175019354724539766463318160658851289' - ssz: '0xd9e5260c1138caeac1cc1acf61b5806915c198fac6b6fc' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '11825686541981180358392336899912697834165360564728240093' - ssz: '0xdd17e47525f5aa70d0593d1ed2e9ea1522addb1447777b' - tags: - - atomic - - uint - - random -- type: uint184 - valid: true - value: '19344803720702268208265842079944300932591535148420015772' - ssz: '0x9ca64b6de15b1b8f88663cc15180f8e2e7854fd41bf8c9' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '1381279380569480472996584911991522106128827020580318540723' - ssz: '0xb3f3120a928a7bf5dfff2d2ec72fee3f9185717dc83a5538' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '1710800360345507530608903952563366286992335432164890617224' - ssz: '0x88a5cb9a10b54a766d1c42899e2c65a2a31bd042d496c545' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '620810176017102301644122502129107262137975866296329120839' - ssz: '0x472c3d04c11a651e9e3a689de90993c8c6833fb6878f5119' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '3234484202787321180763256591533362264040520567185285133310' - ssz: '0xfe3345ff86e8dca89e00a6013192eebda31b18893b97e983' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '1710414927849226139402721391980900407562101499176327951406' - ssz: '0x2eb4eddb14c0bd0c75e22d1f5f587b62cea02ba5a890c145' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '4234820064615624905197098800651094750515964588498002720149' - ssz: '0x9535cde60b8f793d97e49510c3b1a5846887b94e9f95b5ac' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '3653652360078988377986388157889634958581818092896230664940' - ssz: '0xec6acd3b4dd5895ff124e6a002f4f27a7bc26d4917e90195' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '2058165680973303953206524023772926238779694820250119130497' - ssz: '0x814d252315b34bcf05baf7033c74998d9ad43d819940f053' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '5504017444858969306807185960608372450767459090170021596526' - ssz: '0x6ecdde95364583a2472b790603f3decf1c123c21979f78e0' - tags: - - atomic - - uint - - random -- type: uint192 - valid: true - value: '479923403305856306058759303564570452545807455244817138561' - ssz: '0x8103be27e82ecbf9bc76402d2f75ae823029c1fd55a29213' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '425164173630217684551615645081991927006977690943201695416534' - ssz: '0xd6c06ac4f34f19b2707e24f8f92da53611a93d3c461789bb43' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1465635457103795858794674849552051561422465264844226680368909' - ssz: '0x0daf7cd52fe2a806067bc48630b09b988b22ce5b9b273c7de9' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '525096906449109809970891601960585512858850731335422818314776' - ssz: '0x18ea064f69143c03c6c968f531be56382fb8368eef801ba753' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1548795583015129292733586184645532701928115700397613702277893' - ssz: '0x056b2da9ad4a0be1f596a47e98212acf372a0df46d61c4bcf6' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '441023884481641192600575611544719376726303841305791782489039' - ssz: '0xcf8bc88b9b9c5e50610748b4422a08d9956c2a14c032584246' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1010853716254998192470227443819336589901876310467059473363474' - ssz: '0x12b2ae4ae3df5362da439bf1d270260f37f76a35df3bcd09a1' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1417764795294999049262609545857762820325438799272884643122886' - ssz: '0xc64ef9b9041e40bf1e6831f6905fe63f8dafd9571320ebdce1' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1106402620958017563189322241320488113294182177738518553323412' - ssz: '0x94671eab0ce6cdb972a7e6a8f0a067a852b5d53973589642b0' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '1575690551520719153265351098016322227672993470929277521564749' - ssz: '0x4d14e50e2deb78bb585f64a1061bb6266ab4795a21f4a005fb' - tags: - - atomic - - uint - - random -- type: uint200 - valid: true - value: '721944794472535788936011009064996792975025604975751746647746' - ssz: '0xc276b9a01edeb20ff5de490666c8d03d1cb6820b4d592f0373' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '283788161184204248182878451972717653883776761810554986240576474' - ssz: '0xda8b0ef2897964a7a681a05378190911623a2ad218d3f90f9ab0' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '178149934634732678720142222342160460720663581271507967466478157' - ssz: '0x4d1adbf8a64efaa9fffa326c041dc722ec3876e4f11c07ecdc6e' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '314843156758203159288032619652138702470431414064765132744759744' - ssz: '0xc0192d54ee6a62ba92a69efcfd5308c9a3a44fbf59059c68edc3' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '34509993099631611835293559721950077716317052391595715465491278' - ssz: '0x4eb352bc906a0afb8a12c8af8d9976b435387076387653c27915' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '140948492312106658580155794881036776529232112604622005191445353' - ssz: '0x690b929091efe7eb976a621fb8e2af688e4936f47fa0ea63b657' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '195301538056856531014786538472907670770460393091516818019689797' - ssz: '0x45a50dd78dd980bb021719b3ab54ee25f8c5631418397e548979' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '18083990873295815222255963237198734377161511626624015755587681' - ssz: '0x613013d7f78f08d453ad16d21a48202da8e82d3fc64f2af2400b' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '124077408888453943953963699828704442309312709665786018503852592' - ssz: '0x30024c094576107fad4af116f4d1bd5bfea6f04abdf4f0ab364d' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '323006752223052111410620093630126696963214425103554275092146664' - ssz: '0xe8299b67ecf36f56d637144526a3a6cd1b3c087e448fc5f101c9' - tags: - - atomic - - uint - - random -- type: uint208 - valid: true - value: '385800404979545497299365972172020453206788670887888060284461316' - ssz: '0x04e1c803013e8e4fb87ec487e8e589e6a54ac9499b30ea8c15f0' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '55277705514401252414282420959051933790201578867045715128653849284' - ssz: '0xc42232fa0b10f1087b96ddc567982388e93d0c926d20568d665f86' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '25278232180119948717946455021965622507435762748550013669290836806' - ssz: '0x468320ef7bfcd4afa815ce091c06b77446ff226581ddacb8ae723d' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '43619923706358074353058852510590901840184970849846219143622330701' - ssz: '0x4d89a2c66302dbed41dd2e4a246bb4fe54f5a4afd4c317c3be086a' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '69388733346001031413883370721266766925401178816895921762591326011' - ssz: '0x3b3fccf8fd882940640a7f35dcdfb11da1e1e7901d4552fbb6aca8' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '104229493646722114105408097596578013912698131892142250796223199470' - ssz: '0xee783658b138fa5cda778b4a76bb2ea0fdd91d4b9449b0522c5efd' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '213315815603614491605259937972907736494189135089334060132376440' - ssz: '0x789f64c84d265667eaabc7997462566eb8e6cafcdf71872bbf8400' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '71895890286116524197373427126548221259211153238166419878578268148' - ssz: '0xf4a7d0c9c2c3082458f38f91c675290b0aa11f7189903720ecc4ae' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '65588025353358308968494336853601597777797707720963555263879430904' - ssz: '0xf8c21d8be045e49ae79d7b62758e37c10668446f4cc00844876f9f' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '66963898818471239274826191602149519993490641805785201620344829817' - ssz: '0x79f7ca4706b33df225ca1842d4e0b1890edbfa8667a2f78dbcc7a2' - tags: - - atomic - - uint - - random -- type: uint216 - valid: true - value: '76023155346607127955535532687539340958454969079686872613133461762' - ssz: '0x02a93fa9db5a8eb3c8cf77ece63612c8bf7433905a4c576253cdb8' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '11322691247890750772785343433720188326066540124861398076924282597103' - ssz: '0xefeef83d05d74346d770652f9beae7f1da2e11c26fe32eed0ff0836b' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '5076003068668970296658189715938670726627499368404532942701260967131' - ssz: '0xdb0c1ce57e038cce529470cfce5d7ab47f3bb519ddc33ff576143330' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '20557682686888479857009315837853316385879769103168261658025237427811' - ssz: '0x6336e8537c7a331725ce984e8fe2b6072caa157e81e5ce0258f534c3' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '15709270253336590930371927630644925249864297345261298308078636023008' - ssz: '0xe0bc4eace9aaa663ea1675b20d4a51e14b8f92d24fb6d509e11e2b95' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '7504295153069115448819097176322648337476081377900621007107081499888' - ssz: '0xf0f4c55ae73371d4ed219c9132d9762032857d904d83e2b556ee4147' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '3648758727978778269121534333760226833880358322439075676236502986426' - ssz: '0xbaee6ed2d39b38065367e96578094679696fc1ebdaa78d8521a4a522' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '1870300476214775364826227249444100765260639306571992524520152629692' - ssz: '0xbc01dc142f17e090e4476ddd916cf15896e56b5c89772601d872c211' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '13789797499784360192730140591789737021141348067067272581281317306996' - ssz: '0x74c262246d617d9867dfc1250dde7967a317daddd26d5c4e0d24f182' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '14008607891539364363854600709859623729159364542079851236226236266270' - ssz: '0x1eb75db77ffd99c389293cb9d86ef50b88c2d4ba4dede1d2170a0585' - tags: - - atomic - - uint - - random -- type: uint224 - valid: true - value: '4119995425035813947864210422478242206619061080259737437162312141917' - ssz: '0x5d8cf5e88015bb278a46b5c1d20a71e66e31e672a57b7f8d72271f27' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '6302993395515168221845816201170478685143920727994649255486463874343378' - ssz: '0xd2a1ea5085595bd150cb5df23c3657123d0b6131c889fda5a73380cae9' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '4602319844841649035279470304312522378416834284140043508823278007580251' - ssz: '0x5b76639c8cd61c3dacc8f0cf0d6c6b75d303b3858ac3cd28cecea3b5aa' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '1099288187097276898660820007078812312221652881714273838840778879221788' - ssz: '0x1c401915c27612d2cf1086847befe7572e40a1008b481ed04e8e5dc628' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '1634758649409831258452410223755728597460224486673488004542273149265312' - ssz: '0xa0e5c860799b2c8308a1af5c2932bcfc424360d79cb088dc1625f6a23c' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '246012206746276459681518252952824815508591726617234399689920233341296' - ssz: '0x7001d822a9cd1f518dc3eeecb656d1057dd3be2eb343d7bb1c8c062009' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '853158106319162415882399907417783501020742036531269976606442466045022' - ssz: '0x5eec7f56d8ddcce2d5ac839b1deb7e310aba4c0bcd2cf169017938a51f' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '1076425980086328398511627015378358142745884577942760134042486501867260' - ssz: '0xfcfe60cbe9031bb6dd9f0c2bd0429e5ba43b1cebc42dcfd5f49b46ed27' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '5700778800698434104601360353002809053352488223990034553114845943559416' - ssz: '0xf8f47d41e8021dacd54e4b4ff7720f90e1175ed91294c3cd3e9d2174d3' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '5363662116775053836611133807417585997218890869025950508733033688868148' - ssz: '0x3425402ee034db07569627740c5e6acd864b9f43612dc430cc5904f3c6' - tags: - - atomic - - uint - - random -- type: uint232 - valid: true - value: '2426970447728329518602430352580496555036146161668756408998123123794387' - ssz: '0xd361681049498c5b9475a718c8e3941f6f2bb4062a01cd59835976055a' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '1613049271801253962588016060890794346945585061329522177296209138104993877' - ssz: '0x55085d671015b39daf52c9b05e7947a7aebda1e525577e03333ca352b7e9' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '284278524951509607139599097561020878188408518051207212543439289862518734' - ssz: '0xcef76eca0f65d68d479cfabe5d4e25dfd786e1b177e8fb7e1b0afe793029' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '116870510029841554229455805612971786783316051525887540746355013704544311' - ssz: '0x37f080144ca8675589e8c95b8d8784f4615f36190487ac78b670d8f7ee10' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '130053699757167973056104805468309518282725038708228984820162614857194520' - ssz: '0x185c7e27dae2b7e806b63f84eedf22a04da303ceaa287e491f75b7f5d712' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '519051656733957209185197660636401147033409105171004180231442425407577284' - ssz: '0xc49c2f0002856e60c7eb725670032828da1dc5f12f195c8c74892bb2344b' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '857209832652585106857646102249590523540127109077609264100370048423188655' - ssz: '0xaf581a296885b32c1fe181c7411abeebbc99b2281fe8dea3fbcc09ae337c' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '1706457427187624006528264292822192095256082643152135663515387263171331087' - ssz: '0x0f8472f1a558ffe0afd423ef6060ed9fe78809546fcc12f2d1e81a0640f7' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '849109624703413573761136533648225222034100968742834369829476169807133952' - ssz: '0x007d65f504784de34be736a0457eaeadd129ea656da14e0bd406f739077b' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '798751832024326864425928423093545919725985458621787481096477038033461891' - ssz: '0x8362bba22c641548811a1d549436862b6f7e5af7fed1f93cb20e225abb73' - tags: - - atomic - - uint - - random -- type: uint240 - valid: true - value: '487639798004322277613230212642596105802412093780566513839874380887430829' - ssz: '0xad16e329d322dbe04e20b66b1b8980761657005d501463e066cbbc90a746' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '5099489647304605696126349609305974961708701007683686387353437839390036625' - ssz: '0x9152f262787f9e902b7d50c5339e72030c108229b73b28ee202f6a95dee202' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '17649009580055176422669550057659989046600703500965554727940443763516329483' - ssz: '0x0b4edbafcdfcd063b475edb7d7bc34cd70b8052cec3cf8ff19ec1c262efd09' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '426199882223198595784251717646499098659538250947738478072106027803515843619' - ssz: '0x2374c05905194ff7a2f1b718927a796edee04ce51903a06f689ee23e7838f1' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '359189970573997074902092557607433640165941496064453371629708186263557438009' - ssz: '0x39faba6179cb9b39701595ea71141465ee39743da21130a5c5cf2e7b584bcb' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '429290773623992034469666348980875106571394782174536551126643345589487425085' - ssz: '0x3d56ce8648102e5f51ccd68ad5e88f05d6eca19a7f1e929c208593c74ff8f2' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '44071259082207109492646259745674705684281377345460348117013318839845904178' - ssz: '0x32df0964c480d0f6b23b48a028144e1b1a28d388fff9ace0248b41da85f118' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '160026297177693655446406343130987334279420779393054189127212788336074336200' - ssz: '0xc8a7ca845bd5e0c0edbbcc0dbfef1832eb288ce0241514f57d31f44159925a' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '263345946400208064390327089917856520960587585124961183807472163960806207887' - ssz: '0x8f7134b929216c95aca61d53ce72c94bdc1d4f612d8c69a29c499d0a6c0c95' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '149948968350894246575004866141077320508770472064872338669574783547940204989' - ssz: '0xbdf14a35b4f9cc58897c58227efbd421358d3c1cec00f69c2bf9615b3cde54' - tags: - - atomic - - uint - - random -- type: uint248 - valid: true - value: '276130070408210503339928255499048768702383103126254742237401470668835600958' - ssz: '0x3e3a03251dcc83e9a2a44a6019150bfc3a7b63bd2b4e68beabdc338eb9489c' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '109853385383692125130666181346655966905089281798363364577698721873057727288542' - ssz: '0xde940a3c050268e17ae631eae5511cfe79bde96052f0b5585169e8630fd0def2' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '80831061953558606121992596128000436342083741576797050886075787772192693906376' - ssz: '0xc86b7fef4e34a9e140f861846c28581bf78964b2620b7fc7e81eb9a581c2b4b2' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '52410806078160188458272819439265780457914882846202556927297697991223286362608' - ssz: '0xf0f1b65c9cc33ed1265cf3b8c1780f7b7ea07f51f101af1bfcab0cad0a77df73' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '4528169361101625426609703673506975461869016157183845523294323294399026776337' - ssz: '0x114995961a6bba6729a1a3556026ac3b3653bd81793798df01469d7460da020a' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '74684456646805550896660539760345239771784850672086988748411907468011016586021' - ssz: '0x2583b89e18f20f1a00fdc844adfa49d5e588eb81cffc827db2b7008d8be71da5' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '7930821798834217597582520218130251175929961482155689399092862005846980045213' - ssz: '0x9d29de9b4b00e4d4d8c4b3eaca82c5247bc5f874c4c19f11d5ff60f6a1af8811' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '55845590622716724553703978457616024170428171858378863327115341734776712963062' - ssz: '0xf6a3ab64f441ed901386faf3519bf468fa375f8e1d229d17bd8cf943f27b777b' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '22985072167011274730947499983037735489455584301976188610497015534447597134713' - ssz: '0x792333dda772840e7800b0d23a3561aad3e60523058824963c96088ffe16d132' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '90320659887124956444946788396794059667012474298880656657355653544672084590356' - ssz: '0x147fbfb01845671bebaf65ee610a1479f4643e8fbf60e758aeb2ecdf8faeafc7' - tags: - - atomic - - uint - - random -- type: uint256 - valid: true - value: '41588810815912157824843698140391804743576990512566498679819794402386930701841' - ssz: '0x11160633ed240dbecbe7b7c677a62a7bbd14f6a8abc666e13ced14c8c86ef25b' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '21296001826893306768839983183528384358777935475417962327843917760059950361469166' - ssz: '0xeee05fde12679178aba4883a1e88fba706b794b5c26dba5f0234d5a14de375eab7' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '9083424733960371098764188185142073667453444177630658935049986165458427256084845' - ssz: '0x6d99794879e7d3dd1a32f41acc6bcf7a024152e7a486964a3b72e11e3d352c724e' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '29566131553721056040540973645679176958566665718653088224409538237982402742937378' - ssz: '0x226711586853d1eed51d583e5e564abe0d5cdb2f91a2fdedaa45b4f43e6f8d56ff' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '27386396295611794818626010724225871402912704510020494598477724677995811734020449' - ssz: '0x61e18b3a3550271c3deb5cae0db44762c5f8adf9b5f382639f57fe76a8ff7683ec' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '79192727774743132497929211392962814204097474321636093950599090898303326863519' - ssz: '0x9fc037661da29180d82aab4ffaee967cc75f8f3b0fa48450e8489684d97e15af00' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '15526963993513027896715097745190436309615414534779187135724018786412527388264556' - ssz: '0x6c086d6e1c8cf2fb13fe720c2a474c93a94278c522035a0afe911068e62fee1786' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '21618226575683556926946360788707342858418244067939209080935742917769590393468870' - ssz: '0xc6f746330ec7b5b95deca95321deb62deda8f41c786e4a2e4a0116ccf6a1dab2ba' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '7642799733387596618831190290643929361737669173201938963100440909489090827400890' - ssz: '0xba363c07a2f8d53b2353f0f380852f0b5b58120277c8f6611b09da88635a270142' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '24645895616429953322226564354962746510172899132668958313629564893959254613013498' - ssz: '0xfab351773ad49c32863207d930fd6100e52e2d857f8483e5fbd2139f00959ad8d4' - tags: - - atomic - - uint - - random -- type: uint264 - valid: true - value: '22627560330459972751367815278597636440488178815234860278957928427828952266467576' - ssz: '0xf8681811d75c7489e9bc582d18040ded5e25fb3b7d60193a0678a6ed074b596ac3' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '625250111043137170689751858927250902545171477105610440876043903987621787475440447' - ssz: '0x3ff384792092b0cefe3c1800cf79916f9f59c935154099617572dff9b7d9edc31715' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '3820339058978905481755063485076180968185706583661525507183008492682872693957785241' - ssz: '0x99f65a56b29b5badf19733741f0008a407a166224a0e8d98e7215c84b7a69017e180' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '4849680707369048052211824914630045442619688192743438820460357801220369762493208785' - ssz: '0xd118a9c5137daaa8e89fca22bd2d00616ec5033501a7bb92deb2d2f9618bf7a89aa3' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '5093289363124942642069730573322416122158704929553182919117930150942991343979209473' - ssz: '0x0123fe562b65fe20843e8d6a759d22412b4d926096d81b14e1b8a290fa806481d2ab' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '6144571186318854496947375244157314153979375651725952147276695635525904368159259820' - ssz: '0xac7c61efd63b086979561f0617806e726da231b969c355e3d9a58901f2446e8d49cf' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '7242940294389022311959343674777289374026560764572510438623980076056939269565263104' - ssz: '0x002d65f50716a3c3b28177c6c93d3272a9fb563982fcf26df412b63d6fd1d24057f4' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '2847221820608387398617203755825774542746168121608423732730320846973684286967713289' - ssz: '0x090e8feee0b1f6ed804c1826d9cd07f85b6ae2d445b5ba85915a3baf981a6a160d60' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '2354060005572638077449234149036018236507870338365964979615165922663020432038720252' - ssz: '0xfc72c64c67fac9ee98dc8e845fe382a1406754acc1ee6c1fb0fb39f2446c1a0f6a4f' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '5932627088533055643439309711698449984347199537767722408629723169384113267855997012' - ssz: '0x5438f67705a0ea63510983ad19a50830060c56695762007f3c4c2a31c001e22a23c8' - tags: - - atomic - - uint - - random -- type: uint272 - valid: true - value: '6698873197610807542032168881416614265680118672478957820712945650802555946736300385' - ssz: '0x6131209e4f5e527ec64d1be692aec7a946c61b92cd41c6ed84e29f3613b51a99fce1' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '1313825061500410038993240043130374517534905517915647144891011803618969082282703281749' - ssz: '0x555eef6c7a07b3ec8f6c4ea5501f52a2f5a505fded035149a755aae2b5b7daaeee21ad' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '1820559996200452948457373345404221922955244215328143934805596340623460877962024999783' - ssz: '0x675b2a700ca20c64c2ac5b70373872fd4ea2c9a935744951ac3193d87dd4e9fda6e8ef' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '59405018442386835031158580233415031563454955255687830443447184515710201239397864591' - ssz: '0x8f148689f857e8102e640a140237d79a532954f806d200bb0502247e99e095c007d407' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '90275535968147058728031054784511326125689061347242890714737499032945117265560764074' - ssz: '0xaa7e36344d175a6bf197f49de9fbd7c1dab6295c35b7e44fe53a6e15e2c9b9be72e50b' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '1737340175541908426971661911337498503240358417677517478902063475777658726398133904936' - ssz: '0x28a655f50ff93c838a42155edfe0432750833b77440a2642c91d351ccfbff0973af1e4' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '170992041153025670379739257237344523995717798973681047923852658195840666954694794236' - ssz: '0xfc1b6aed725cfb569f4b723aca05fbd2f8641997b1c88d43d6c482ef4a35c7166c8816' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '453022425318917953329769644003931147605314653128258877161926858702850770550375976429' - ssz: '0xed0dfe860b9fbc7a4f74486fe4a2c651d52fb2620063aabaad3046dfcafd3706bab23b' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '1026374047176903929468201061193303905710441884688478624786261645612423271455804333792' - ssz: '0xe09ef707199e701ed5939bb44d72056ec512753fdf6a2308b0261ba17069a145c34087' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '736441003505661011903711212573788050558633808722090759760702642325456516504505894800' - ssz: '0x904761623bca8c1d81a80458d63ca84a0d7aad5fffc6bd9da1a696cdd2c51ca3dc0b61' - tags: - - atomic - - uint - - random -- type: uint280 - valid: true - value: '54215078046337070658914483591387968354971685352520300652696388433184098505836979725' - ssz: '0x0de6bbbee02412d33a0cae8a2c57bb8afa4f420f2a00b85677baf083c0525f8df22407' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '164902953569354434541848228980871926800863812704777025322146572441516435751360384928275' - ssz: '0x130a5329661775e84e1fd67e93e1cad12ebb9e056ba31ca356efebdcf9fa0242a67ee254' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '291531052912787807064587765399461836950404971734993519532387400656978989727882073504126' - ssz: '0x7e79521125d563404e900c92a13cac1a96a84c85b3943813f07279dc47fdbdffcf391196' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '198448216393272029754165267065719248322919651114506823200862937599118495878516498204513' - ssz: '0x618717b54c098b37f9b8dcfe15645c2d904995b1f81bd2a97c303df6c05beb3a36012766' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '411892664643207499593905341381662462338010666761048511981269030775942279690454488942005' - ssz: '0xb585395909914df9349ff9ff2b611a8c6c6e2eda54276733773d5037fb133a77ce2c06d4' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '17460533610627184952980018110698091129854158298256594138071034860087421027615982467770' - ssz: '0xbababfd11625fd539bbaf04e8a514adffc6fd5b47eb033c833423cf3c7b3c152afe7fc08' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '486902605761996984072152670157920118474014684182270296788772954726563173270703966861109' - ssz: '0x3537999cba609d039807db4afd40a8cd4c475a1d389a9e2ad81d3cb6df6b7a46adcba2fa' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '86601162605024166638930457660265166272892054280267727933558485505483001636302956248958' - ssz: '0x7ebfbf6843cd691f254a9314e43df497b6c6bbfa98738476503528ff3539fa521d15942c' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '415512347649363633615608669788780842601503035226699026576004878065364393031370209020801' - ssz: '0x81cbb43d58dad9a0005edc6f9c1873ac6129e0b2fb496749c9380608f01edd05ef2ae3d5' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '208177474990117632190045625073259419885562430564096808744447170026464229462577778502990' - ssz: '0x4ead3bb1373b4084223fd8231c4d7342f6cbde984cc45b0ee75c34c944367c63131a296b' - tags: - - atomic - - uint - - random -- type: uint288 - valid: true - value: '410024872315579396771779952548496199098180743028586455759125340883433037846147751009660' - ssz: '0x7cddd4ce7ca2317aae353a6221e1d507d0aa0d3d500bc314b095ec4e3c263219c50a10d3' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '105196538303486936299998001691849159842180040131100966356595522037239359106506771842593406' - ssz: '0x7ef275e7462df1207614d6f533140b705bc2e303577dbde4b434ffc0b96bb75c291f8686d3' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '51401986902242622175928744574404491512752015460158275286825691505216304697427029818172654' - ssz: '0xee64d1efe77948ed6f5bf00e40200b2a9f1e8cb5fd040de36ab2a6da47333486ea01785b67' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '98078353550630176427424854707064791518279897156269078658369592408854315787454868458812873' - ssz: '0xc9b5efd8761c2533253ff70f38857b69a395f52a63478a61a85e6a8112a44d63a5b66536c5' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '100830145923399032657621993603458755666686247126234381146193961366559866084163715771765068' - ssz: '0x4c9135d3be8ed0e4bd05ed14e23bb302352529f61d5533bf8a67dcfb5e35373e4df6e5beca' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '65843753989403608699845175432897474238609522844359758989686457469464177970425632333255058' - ssz: '0x92514c731ec091ac89129a46fe5c14fc5c7b9669654815f9b8236558f42b6ea93899736584' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '63381984136332901239253547271139676990845360685433698809319737558643681492590147082636158' - ssz: '0x7ecb9b0bf49ef8c2a3e3acda25adbc0d24f4e2826aae21cff2302911ee7870b1f5c83d727f' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '76823274391392865977254749209125429961844369033881984135623084447348576343281508069368447' - ssz: '0x7f62efbb29e06bef0e0e5fd58d51fddaeb7819337de2ca9bcbad9b652b6ce156e61039799a' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '84501721833371540610803467712558222979219676711022996888623254085616047539546803853344449' - ssz: '0xc13ebc70679eaa23958bb67961b597d1e31dc04b321e04f0885208cf679073b3f479bfe9a9' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '109505011555658906559217152478192322548367745826318087755717419364565250718496359318773490' - ssz: '0xf25e63805b74434c1c69b1ac9cf39bd0b04dd4c144d290900839e2d7d6bf383c4ed85530dc' - tags: - - atomic - - uint - - random -- type: uint296 - valid: true - value: '55140007306471310955129196374170842905278024706787194927419557614353926194973854166432805' - ssz: '0x253c6c1a11ff0ddbbe64a0411a949ffae77e3dcb847c7af190c64400bc6951d32be5a2df6e' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '7518424305389828877561448802209599682291353601478042372352335082498834968636952446200139817' - ssz: '0x2950f37f1fc803bd6ec9ff5cc29fb5dbbfcdce5a89d07a16d5e10295af5f936e919b35c80d3b' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '32351462780096859033766424413351019457418357887408473237065469743770778631534554645560543251' - ssz: '0x13c867354bf2dfdef6f1bcebaead4a6228036232c191bb5145c0392f930eaecbacc2c62d1bfe' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '31370641032612024743654524297848040315845302018231903378547610677190058542105443885708700641' - ssz: '0xe16b5f23f26aed50cece9ffa2965e4fae99932a856fe3cbf36433e46e18a6d7cd72522fa66f6' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '29189197768019204867361776509209878880250265344801969104058925326075443201837639541643160457' - ssz: '0x892bda280b19e6e56d8d901b1e9e2e8398284a4295c9158f9acefeb6e0409167986ea69b44e5' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '12126152267791959686806893791657751717575305372984499660774677878023396902925223071441407734' - ssz: '0xf6ce1ad043d02df0fdef34c69e5f9dc9b6e2c71cfe7ea395c98afac54d28871cd0b5b6d63e5f' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '27754000657791870573424297368620051384566454481161968602787832621717177488227594642163196994' - ssz: '0x42642bbf5d46b1f61586767bdb1e514bc3e6baafb8829dba49199a19525e40af2c23acc3fed9' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '14674509897016689354642901586561390812691688259482590490518819103217534723261716036031762344' - ssz: '0xa84fded1aee5f32320a8c715d075f1b376c15c6454ced6a493d446949e8adfbf95ad7afc4273' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '10974409750203643927728785093722862689371882962874941147088980236456174820334325528543184760' - ssz: '0x784739258759818ffd8501f185ace4e68e888a207b01eda406891235d264ab96a6b59ef43256' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '8773034183720629776387722485242417436235390926235538756449852277065464816500949850089588732' - ssz: '0xfc07a00229e5b4a30e48df48f6b48d275f25cfc5c1b60e2431b327d57b34ffc20898de81e844' - tags: - - atomic - - uint - - random -- type: uint304 - valid: true - value: '29402373314605751227445030990381133455144685719620264224291180547053282505574565188480687272' - ssz: '0xa85c3625c43e8c547e730f943b8845c075d904109e0b0d16d3077e5f6ce20435aa8afd40f1e6' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '7321707725011952147753519443597467161356275940570429766992925176822949145101163238647751878563' - ssz: '0xa3a7f15448ecaaaeebe6347c6b167478a1cb23891b2cc5864a73981564f2b3145073c650b7a4e0' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '1136646014892509587986593444105733028018535708983366340816181237331388025740303052244861460527' - ssz: '0x2f200a12e303a724aeaee827637ed108f9e95062825500a53d5eb190fc42aa1d27c30caad7df22' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '7959246976583376766932076981843115940992803074034967365631330264414213255835832243688383998354' - ssz: '0x92693c86e936824494e3b69049447e4dfef72b5a885035f0168f64aa28328ede4f8313ba4c34f4' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '6107351137933273847655581642494869487308907030068614850868116177240323904290909366998987208419' - ssz: '0xe37660585fba773bd5d1f6c622a48e801bb99f09c1eda6b949b74562a6581ac89d5529fa7d62bb' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '6140802159981895781296786122319823582398722389278504787444880185906342085250453508326485302024' - ssz: '0x089b9e577a36e1ca648f278391dfc30179e5f03f4985099315ccb21343d8ac796d55671c3c69bc' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '8110829379496825846585352861566852060822773039592504816667939006737009639168469140580967804599' - ssz: '0xb76e4e0a3a4be5919283d35ba9f62c0a80b046f1063ca25dfc85082e5aef45577150ee44e9daf8' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '8013905790131524873992548727432508440301237907080100872706721844443952385791641418561998731852' - ssz: '0x4cbae2d81fc570d3eeacd3c88fa7c3b959b12429b85909ecef722f0b5059dec2c69820bd9ee1f5' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '5469482167287631768657761622706498198081450134675243549102001224697264614857632730130716237340' - ssz: '0x1c1e8b9976806dd3e490e5f94fbdbeab825b642c12e88f9cd1f11171eb17b4503a72119451d0a7' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '7167791254484960175051783700220377616479875888435400025094742103567578731988619212784418265558' - ssz: '0xd69971fa227e106e61926091d19dfac46d0182ddbc2475dd8cbde5a03ae1e224a7b62c83c5ebdb' - tags: - - atomic - - uint - - random -- type: uint312 - valid: true - value: '4034975365150538046453477537125307010240073575773401700400915249820066282470197993375060557984' - ssz: '0xa0803564aafcba3c0acd5e5ea00e8861d968934b2426993dab571c362b454241a9726bf6e9cc7b' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1280151611725962382058711679973517217918577786593633773883781861908443041942266852023483892073918' - ssz: '0xbe855589debd4f962aa0a9dda85e82ed3cfc8ce233a53f5f49903af1fff19d74f07ff83c42666d99' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1175629971915001949897604736589156067254375586979584447253152806917540941900023462029343753849759' - ssz: '0x9f4bbd9f897415a212a47e254622725283ed5a3ea178d824dc8015d8342286c24824b741dc7be68c' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1190212051475314698606139837785234652685953546261436241044483618261263943453052655223505081533798' - ssz: '0x66054f05fd7e170b34d42c315251e3f48da66e32bc569a9ab314ced46ab7de299a8dced886e3a58e' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '935825875651506998460550668708356905058224685295494697882989368813306095457057887930891805151278' - ssz: '0x2e50080fc542ab552924b2fb01f2e22864fc4dc33be62044b5e16f9dc42e5fb87a410c8fb4da2870' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1444771337963886936020720722474050000290360243901646522606490622767404470616458484628471375389372' - ssz: '0xbce2468cb53f2ae6b4bf346a76da4ddaaa6087eaa6ac517b116cfe5fc0016b380a4030f20d3c28ad' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '666618525183652677682891603976464028075322822724612208655574574529974687587035550946688961240340' - ssz: '0x145d4290a51c243c51a02b051d548f0a0c06e8c9211171180d84d6d2b75fe0ee9fd9e8ba3b14e54f' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '310730716174623794305164795786344278376287740636880367902788594348308391725324646649798405379108' - ssz: '0x24d4b7246be9ebd2f59a0635129386bd3be3d593a335eaacb328dd0001fd0e6b9b548d20cec93d25' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1511194807021601526493178344009798094923477890379428371286260842866384534788971275693359615142932' - ssz: '0x146c97e1bd854d7163d33f3bec8eccf0c2452fa6589b28a31b4ee7bbfaca7c463830dfac7b3a1eb5' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '465372998647954481528389514361931743387897694193689723021444038397600362756200075803515147171221' - ssz: '0x95b5b2195c8a8c59fa0b7a7d6415ac4517a7455adfb9e489299eb09622b012f8c2956048467fc637' - tags: - - atomic - - uint - - random -- type: uint320 - valid: true - value: '1392026254506891223414192256806461881034325240247704713119688191365785982202993807741225129224801' - ssz: '0x612a688d99a37864bd13c3101af5d92c8d2b25607cae211daead44f4dc060a970cf891e82eebd5a6' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '284988847798035986172445340697640116528123252056215432831103662315846113095178978363436458612888737' - ssz: '0xa1145484d1223fda4b627323a48838b73f63c8de0b08fdeacf444fea9200f8751603e924a7902c6c85' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '481163248994344932327086593439194971954733697819448144818934921492535272217422580916080330314237927' - ssz: '0xe7476ae5e076cabb169b418950e1f031e2fae8c20a7292caf6f3792d645a33bdfbd884113502db43e1' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '37713122233406867112389913619064826241026464990375425715278617740965850906506127646621868994789181' - ssz: '0x3dff4a621520b18cf6c83820c8b3b0c5b35fb8b5edf762b62995848a8b2fb991dae2e5260fc3f3a711' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '223143814154153834480288820840079310126192620985126455610005544398021316173291328672516391704603758' - ssz: '0x6e2c2e4e3a10e09de48b947144d32884dcbaebc269095193d4f914fd79e1756af260cb35d17ffd7768' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '75627809146869484805456290305203658928336299450275423329769371050780250248552883679013729632538619' - ssz: '0xfb4f48a7c365fd2aa19b4308434596337785a63b803e9f3d98eb5a1892f53799dd6cc360e2e50f6823' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '8171589185932715690517868485615562735698552458005813767713009896598796768220908210197686908719620' - ssz: '0x0492fda475c9df085e3b87f969ba9532d042c77090231a3711319884038d9eae1f4348361e585fd303' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '427816883694258491896164157434668562016235386936369841132276225214380068748949676033754787082305155' - ssz: '0x837eb22458e4913c566328740e81ca788a8e66174e87b19a0132ac469478ffd53d0522a6f0ac3e4ac8' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '97552355299263564137036718071617146467157639218042532980047770995888761147038560480035536803479989' - ssz: '0xb5413c54b17feebcd36d7cb83c63e1ef3e560eaa7ba6b3e541f2eab6d852264cfdbb95e0e02fbdab2d' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '84245200729750627814085799092386285073046710095572604620881645141898909599893245039522911503997951' - ssz: '0xff5b83b2571d816cab9aa9a6b6abc4b9cc35d6bce201fc6075130f65be231509cf8889240447dd7027' - tags: - - atomic - - uint - - random -- type: uint328 - valid: true - value: '169490407166194822469304021843335247417620875210077782816249037678717628252460830442933554917466185' - ssz: '0x49e0ac49729c23a1962a45a9702ab22724c4d686f1b822307f4f81d4da7c349a8865417d669094594f' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '44174223538517922327555465343440446610374783750947128279358659579572008955329968620388752900331742397' - ssz: '0xbd24dd95f2ee0a260f354de06c6e9792469aec6d09c8ce43323fb6bdea5e2b36d3eae41d10ac18f1c850' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '83675237983202871713688981362264876300857685244709258351226319235646708519538261790055079746860542830' - ssz: '0x6eeba823037b0271619883ea1d5d53d92d354689f8407f6c3e37d9ef3ffef12d41dfcad6eaf0ce090699' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '138380135856147544878424920302401266357159268922633543940176204557093965647900659327498319664538422874' - ssz: '0x5a8e03c0bcce5e787771a992491bd5154496b5ae6a2cde5d8923bba5dfff3ded96d038197b1ddb1911fd' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '130368017015493906067321069866296529103524452420956632032538950831138514747905670119637807342815417627' - ssz: '0x1b15e23e35913a85691ef00a8b2ab507b73d5fdc96a7ecb58b98ffaea092d5cd1f54df96559715166aee' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '66517119328379000697800735949188252113397945605964965827126954467345410080689077986809890862598506936' - ssz: '0xb8c94cd254379242c93db4bc82d7f995c04dc141152be5b31a6aff8f720602cba9c8596099e89729a579' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '108155759662685931858169535971104216170716666966185640709250854567131368708478379204842871931918378676' - ssz: '0xb466b4a516dd0643cce33ce7bf5664c66815684e9ce7ad15ed2b305e64f71b258b3e2f730b37b906cbc5' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '2107872012554454467445617570283162852459726237126746955646237078906261202628394888572177844795515377' - ssz: '0xf1a1826c0266dc770f717d9cffd7cbd7349fa69133195cbed3ab7e84dff7d43121f00a29068463d6da03' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '74117619849119497419396576007196371738554735775787354150844672011820444650691971798248787103464569862' - ssz: '0x063c4c4422d4621b2122fbd68c5f886222903cb50b24d141379ea5324fa81b7cc68e55e1926788788b87' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '4352487931763785862083469414626776434909901989212521068018449563551859037052517921781149112783109500' - ssz: '0x7c7df08337eb76675443f921c53ed29b982e567f4b51a444521a53f37a409edf2c5d072cc6e5a8b1f507' - tags: - - atomic - - uint - - random -- type: uint336 - valid: true - value: '122086677660824745687740253193028930339803172296557011197128180084781713031308571537483280111710962497' - ssz: '0x41032f355963c15617b0ff42ef3660b5fa6afbb4832a5adce6626ed0ebfbf81bf33655a876e7fc0745df' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '9139356519165700471586541434800222489413081411008919747447462180231340958915501043234454538292077862689' - ssz: '0x211f654fafdc9552aea63d9f595b77b88ec89feb2e334a3105a3965490b209699d4984c706e468eede4941' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '12454144626129263155986519241337546384755799642425466384456680461447344392808017265591419673646040192892' - ssz: '0x7c974df61dc716a46996b91ff29bfd3f847a845b5694dcc222cf94b8a41481e9c6d1ed7857060071e3f758' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '4105963924503838753238786172335095828059723991737428927166942517046574817330800425321763927436644781908' - ssz: '0x540f67b334b4e162b4b292a74ea2e17aa919c93c49bfaf64561017a3e9d387b821aabc1801d0fe6be7541d' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '32419657378762022456021675939205581791665531882382779500849615958076261762360323301790223510018522800231' - ssz: '0x67e082ade75a5e56cfcc0800875901f89691fa24c9b5630066fad917eb94dc564d3fcac0fcf275566a98e7' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '12270744730360040894454767065328525199545148960897819898660160262878615573122273205524375222544036093347' - ssz: '0xa35dcdd8be1eca32d698253e6451de5f8bfaabe1406061aba9be4d92e8c71276f278f3422f6bbd8b7da857' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '22395267022711250482952868057164684181088528903177786082749703003391473790433361589243988116805777501742' - ssz: '0x2e2e02f030352173c9947b66ab7bcd037fd96e1ac54f3601e96c6d1b8da16254be1387b9276f2d3503fc9f' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '20690904032281624295011945014721547919707948120891859124736840427817022388447502451987632580152924716899' - ssz: '0x633f768b5122731d2fe0428066e136c759f61d4defad89e326a0af17d50e341a1e47758bc3d9d39d1bcf93' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '11877141314993021016954194306504736626651123702775950463244543412266185453251930565233543655819786102077' - ssz: '0x3da590bda5d8980feb04ef3e6609caeb8cee2fd6c8c67b1c13701baf41ff1f2a9d53cf71d10f632aadd854' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '1953290876303443394777910056475728158953115814051097963044187535866142392488406044263712020600236673554' - ssz: '0x120a1a775f54014276e17be7790658d45e4dbcb12274f52a92799a70d2d962b45f42edd40b4b299223f40d' - tags: - - atomic - - uint - - random -- type: uint344 - valid: true - value: '27338175044291453712140260733064284621619330318152291105138117509157398191103534246665631787541238331108' - ssz: '0xe4368b8f0e3de660ec4f2e04d2b0f5f5015a691f1bb9b619265a4f4f65993615c9415da17f5abec4804bc3' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '7678086807425371999861606548598701872056517907912188061224822352540192165763258712376032254003863205101968' - ssz: '0x90c16a352773a941f68d29b9766443626e49c23a01c18e76466527a5999a3698c9a13281f79b4b8f41ba41d6' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '2144016186843968409162995311801653725362458281467257473567339992375907602458578798358365850304568635898297' - ssz: '0xb939c32f6518eb6cd7c8c9a311b265ce106f24024eb5c9963de8c16b48af71f856f96bf2beb73b9a8c25d43b' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '4240898854339149166767265184610866422983105455755884491989987475638493644920258184691465349421876488484876' - ssz: '0x0cb85ce7beaed64062d736582239d7456fb980c60759ef29dcd0be2fd9e508e148c4e438a0d36be644965776' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '2267765604112132015913934377577242098571949666399376033279589762745388339201981915105262126920334985042319' - ssz: '0x8f9986a40afcf105e1f94f5f7399697910cc349f473cd3c9cedb06f1acf5f4b311094c49825df4acfc2b483f' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '1906927330387057667507670493332998403124220485625896134099622262546438797493513408858110563349450966106427' - ssz: '0x3b0177161a3f16b869f8dd84486088b12c4ffaab301fe5f098b1cf8d68a0aa67ac4f0a9dc9a568473b763635' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '7086066947625248993755831198806799984128253742827802484157987526291352476242037095522112821873772034149929' - ssz: '0x294e4e4d6d4a3d784dcf338cfbfda25e2a86d64d6c97326b7f3861d1eda8dae929adf795d33b74a54788bcc5' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '9084373980623817999046029128051007464179264197951875296738810785590122696547328340823448931298876631987815' - ssz: '0x67b6be58e2e989093592a96c0e366c70c26269f5849cdc70b1ef734f8de3d91078f784ae76c10c3adec77ffd' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '8047865582850239427856866986125679812555039836372233911437853300223218665465829731451549914633020165675515' - ssz: '0xfb59253b1e917160fb4a2706f5b0f99f575ebf566709ef27dd5fdc2e0da360d20beb12e490af427f384e93e0' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '3640715329630045910047011955777626753599726008287032631194279156901669149706776155638292774937236375022005' - ssz: '0xb5292b8501f0d2fcd18077e9216c0feb79aed7ad210af06f9f5bd8acae03776e48a7f42dfeba184abf129865' - tags: - - atomic - - uint - - random -- type: uint352 - valid: true - value: '6063642904878355403006067999976167117871384236865664680515660834238680000941876926792928949914280231130202' - ssz: '0x5a54bf4fec7c3af548400588c92bb1092012ce2883f4947a6bc76828174a4ee51d3b6be5cedd4a1bd1ab34a9' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '1030181877056595731690201962923191361856531816302288790497392258892826467773778920593443574871539481764637797' - ssz: '0x652c67446020f254df7b96c2281f1876923e5c11a270520f2c65e6c332fd9ca664720bb6724136d4ec99304b70' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '1991381026850522454713510734760391320479548940420627171516120123676750899557811390817244436065786725532068724' - ssz: '0x746b16ee719ce6ee33896c74744933a27024324f92ab568c9be76feddaa7b234bf75ab60450546e0e2476b11d9' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '146794669928815198323400954401957339744024778999029681693279806431115549894012966307851981521513556475535776' - ssz: '0xa0615a0a87e0eb0a732862cb01d1ffec9d596817e4c96c5e937fcf01ea3f6a4bdba90f4f321ad90ef0da4c0010' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '656725067748292384731507472588331783701485145742323083023223017885219784154340376594969906189701327690291610' - ssz: '0x9a59ee9f95da080be6bbe427196ffddf10da0d98b9642dde235d532bbf5a407875ca3ca679a2cc1429f3e39547' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '1750903063076070506923657454539249642478574196608297479292541570158479179412706359248174516425050391915178280' - ssz: '0x28a90edc187d18720cf9b8fc257d5c80334525ba711753e30e8a052b5b06348a913f141a82db602320c7e3dabe' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '1522102445264777806351326688071644818027244438736771140486430964227191955699356390588587870597296935650212437' - ssz: '0x553a948d7c74843ffc652118446aabba5c428bca70eba0fedbc9cd60522978e522f22b5f513d5487156537eaa5' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '716411411276943594345753534683853217208584367528869646323170456560811475008791461509106937710778849654678370' - ssz: '0x6223cb8f8920e1b2429b65922cb8ee8b04b973641043a7e806e1844e2b33ff3d6194e490ce4686b118906f174e' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '1756869530148095084035317303409584194354386886683533775471781014920610528948012961301372397615401856306907796' - ssz: '0x940ade9ae81eb46724828dd9b91203c7fc4077f7ba09465dc54835bc039a9b480bc43ff1e5cd575abd416281bf' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '650465813811416122446012737287676356309144616844653427499568551064078652664772141117315410997725024474758868' - ssz: '0xd4fe5d0512ca0a026330510035b6a324636fff41836796bd5b3776ae71815ab1060da135ff1509a7d5e539e746' - tags: - - atomic - - uint - - random -- type: uint360 - valid: true - value: '547089254020057132368460768836094886929127607045615628933858957863675757626777874703850719429881678423583183' - ssz: '0xcfe9fea169d15618c5d86d80f80e11cb5083b77e913d0525a3c5dda15c125640278c26526f488430cdbe81a23b' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '272626039890169113235796121293132036228081979284454837776953589827661107639996222967268239173096460043076212894' - ssz: '0x9e988744599c01b92c365e14499be9fef6bbbd559ddc07a6f766a06a702efe01d9fa07c625b2a6ad7d4f44441574' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '540675402282818898678976881371772391804989559128386921125775012153543808061217934033838318848072321496492882719' - ssz: '0x1f3b150890af97a4268a088b1612cac0bf2990db00290fe44d4e8130779831742d5e30e0122ef78b2c6981a837e6' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '20079965529598929486603434055399269942372496350504464133928247628326182227009516631921209501085287816388725117' - ssz: '0x7dc9d897ade77b9eaedb34f6c66db2557e55b1f6f8346cd290d4bd58e3e67e5db3c5f51d585b79c5575cbfca8c08' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '17784704548839280831349524814914364621232359389824864945568465322811926576873927715107747043663039137125003669' - ssz: '0x957130cee87397e6ab2389bfd75694b9dc1a8be36752a8a16eace7e63a38bdeb049a9162354ca2c3349b91999207' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '184995082245894744006198172069733123527998049848534870230970286472848605773454547728513550523237321202231583656' - ssz: '0xa8a3baaaf9d65dde170e55ee94612d302622599dc78295bfec838c7ef76ad3691b01f1c1a9186e640e5a6829c54e' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '258135552691482661088963481080755199064727201036565958552676031058811910759648293964904576719085010859925249385' - ssz: '0x691dc1ad0a0fca6d1e359b61f38edbff3805da71c44fc9d3a7bbf2f5ed159bbc550e7fb81d8b97a4df4cb8bfe96d' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '506447106401391621782825535417559442047221084612017659984944621440090637226692531621687722515955979442769155311' - ssz: '0xefd4402fb15f471918d2fefead207b27331e13404890262d1acfde658011b141443d888574761fe7170d16a5a4d7' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '303560660617314207820166410792184837168868819866373533205581065550244179161802659638224222295498568902860328165' - ssz: '0xe5cc075201a4d98935d971baa8c7a16cf8d1907da214cf767821b61ea4dc344056b4f19a51c4ab50da57cb414181' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '498404969010571329247844529418408144947761593672462021640293619131147447582494129991682313711779381059993961476' - ssz: '0x0484f733e02f006cf259b245db3223bbd93cf8a734dce4c20be71b68a43aedb882bf47090c3a24f76cd2840538d4' - tags: - - atomic - - uint - - random -- type: uint368 - valid: true - value: '370190953423541160654308209939007616910069510509949219105905591483658864965033887394146306398816475799478914787' - ssz: '0xe3ce5ce6bc3593799a8d0294625c5d2f394962ce98de4e968d4138c198be65068a336f9b923a125bcbcfd235a09d' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '111055184911949036136734829151727766943049258042766033273391265708627200239269458091225789509130776239441289349754' - ssz: '0x7a0a9b40b1b0c27db805555771eb9eb54a4e63863d5f2fb9ff6bedccef26ebfd94e85c3924a376c6defe7f0bdab6b8' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '144947245527612210374018137105993380005967937101443137321255030880147795235910973788612463107247421902968713538065' - ssz: '0x116a36215e1b008169b4c02315023925457f5810977c13ef6cf7075744f5ce31b660550b4700e80602bb587df415f1' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '24918892354264929187648520405975705233973156055086727289771079148700792116229325449579736614900086265280567053823' - ssz: '0xff0df613c9fddb92c4eb06865140f00c0938a8231bd9fda08084697786ad28905855a822ca942a9028481f425d7229' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '82132505127051130096881567368862404093487009557008639077059874642241226948849409174738354257739635585303700437128' - ssz: '0x88f8d10127e03aa8130923c136039d79374dab67a9f6936791b203a23b5ec536c25161173166f26afe89d3dab09b88' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '89692734408048000770285467799388956455145122132077680560275472188025834673951658111800011828130392075137824361309' - ssz: '0x5d8b906c3a29c9a0172b5fc5f8cc2b3158cf8344b1655b12c4d231cf06b5082393220977a6c96452f7ade55cce2e95' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '26929326599569992051791749930098981463803494894034161188550796679270807708553116347698513550804357857256085555318' - ssz: '0x768816387adb497f2b668327cb5ece18bf316489b5161596cc52c39a43aeda716cfcaabaedb46b5169f1972c66ca2c' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '116617956336616789310377504840555863154231072233136893729545098751095219482031799338685237022128076777271330025763' - ssz: '0x233133a9bfb7ec502adec5297122b645139b61efa8ff335b275b95a9ae0f9db61bc7b9ff59b0db1dcc9fc91c75f7c1' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '142789823867267321502827807339266813485400149502532521662094350436769418253895789921895601384450140832222571118092' - ssz: '0x0cbe0f86939837e5d8857542cf0080e542db84b405a4131bf9820d0de874fc60940385bec51fd91671251d64557fed' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '49819486254732066582903680818496785196183550481524341933517067489762534929771865412010933859002245116412904641759' - ssz: '0xdf94745653866da08060b12c536494a540d8face74af576740e7c94284598fe44b863be573215d2dfa3e85eaefdc52' - tags: - - atomic - - uint - - random -- type: uint376 - valid: true - value: '20064353672818603224241174606034334937306410937648801428733696431850348173603444173187183367716583063444909098369' - ssz: '0x8185624d70b86a75217612cf7c28670e80c4d82301646159412ee42c2922df7f8ff5e639e354ededc91f2d3b525f21' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '5279086560674718826366959884851424269485574528895956300320184455287389870777585101664114175581452755569572760432228' - ssz: '0x64ae2a20f47b72ea362bc0c38e2da270323a286f97ef7a19b015585c8df469c07f5785397810ff1e9e368652db854c22' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '33749166046018731646348788623618740919928730871231300659005817916558496434983621182856810117061327726088147490248906' - ssz: '0xca18a33cf68def9dfced178c5e7f805006a00aa954e61f7f143341dc6bb9ed572901f996e1ae63f9068232a35dd345db' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '4321681689950826621816734495609392017596300368497816071316146138230462746576841535744375991516648973033867445359415' - ssz: '0x3753212e14ce864528111a325f9c1f806429668c1f9389b5b7584fd5dea1321ca2fdd04fca0c91702dee8a2cb51a141c' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '34284925870822036461118477691429911389596976718740740466481809461177779069185449643317573957502117533521821075231033' - ssz: '0x39d18f74c8e8b8876a0c91fbfacf4887ba9bbc8fd28bd79c05cc13905bbeeb8bcfcdc0bcca2cb1a8e99e3360bfefc0de' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '39123953872888367120425614261905527110740895591538389877835931650715197134263938482945123756165839968498051031340923' - ssz: '0x7b973ddbd72ab5ed4c4306d0f105b4aeea373b217dc15deb3b5fa1f70eb1cb2df1da317a9483bb3001967bf36f8631fe' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '14841420932823149019557945682611580392874941567684108006999108904746957883138811923104195390755449510984606334973889' - ssz: '0xc1f78df0c22a5e9766d828237734ab259d161d90bd96b935eb0f66a5e111ee5b2bc0bf5d86219119b57e86186e396d60' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '28262012021452788433947511498845499609654581012285137839927925554669320570582984054045295543536348489466767522365275' - ssz: '0x5b7f7749f14e6f18796ded23c6371a6b16f5fdd6e0bcfcfd2adc7518007fc2bf9e466ae7cbc2403032dcc0f0373b9fb7' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '27994838955377966757363319384000894815735798395160870870183297422770355992337818879061449696967729051929121146075105' - ssz: '0xe1f78c2dee01b5ecdadd16b02b96054465638f46e24bdfcae4eb26ada1071d53930a4d2b357812727ff0b0fcffd9e2b5' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '9653946316845826710463559064197203155838710537717779493508750113101840191427569072706889928205274626486049371951029' - ssz: '0xb58fb55448471aed53ee6f6dcf3ed596a361b81fed9b0554d565c510faa1517b4988a79bafb9417e5a1d044c9213b93e' - tags: - - atomic - - uint - - random -- type: uint384 - valid: true - value: '18053997788931957919102821737757947924174578181062457122693832101541945307758728333510766154774492968603573809799353' - ssz: '0xb9600bdfb493ecb6f3411f0ff2574958c1b6e154a2d7442b049a67fa50a7fc168cb2728f7161ad46a99e9ef1c0974c75' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '5731739628205919455339762572004370382602294736314565760608149410878624282800048376253171927107459523807334200189022609' - ssz: '0x917176beb38c4474cef338d8e5b9b5deae087bb1dab04e11307b90cac34dba63fea4b4d14880aef902b193450723dd7791' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '6060761852299710477694732029642552099793350773938689409486140131402164197027286521738100474275857073834986260665849402' - ssz: '0x3ad6750724c98b679451d1dbd61416069c0e1bcf595cb1e72240a474f743a2cf1eb27d1c304abf21d8f48aceb17890d199' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '8359341411961963112783459893405628156150200390201294332402885294736498459962888036113630584319310115408463579733425430' - ssz: '0x16fd5d54f64e3e4c3015589b840ed22762103c7d87baeecc10ecd6712b59c5016c2de89b0ebb1b53aa7c49e81ab2bc27d4' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '8507182149926454428585772346079203548820918814534021309542078888134603353834858782750512754903872983472550128046508887' - ssz: '0x570bc3c1ee980d831d9d15dd791eec735252afde1f8ca5d0127373ec7259c188b9cc40a41d8454c7db7e7f239a1a47e8d7' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '1686935923683103158448991139407760420900295000605763177951224648077672317904445451306840011545798675241786454263135522' - ssz: '0x22fd46d2c582a1f5e7bfee56648cd92143db1eb1dac0d5ee7b7fc58feb4f0d5cdb35a4fbc8db4397583c242b926d3ed02a' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '3898539391729495575817437925478146953655330267223907369771855227539339630791488802073921683473738025480662951028952110' - ssz: '0x2e8cc917a78f073ebd9cc31c7aebc433134f767a169162fd1bc781e7f62eb5b714fe63f860fd64d8776580a7775052f162' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '5662719121336147896230557672329921333276228833070396770149921979609535401517883083952205393356356581523235024574488806' - ssz: '0xe6204256c91fe136876a5af42e9388f801770e90bdd250593cac2b4bc04e02cd4b46a9293cf1532d795bf1b963b46db78f' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '6509839137627765955490425164913288862759744769224940662986596794445853437515438025234993077273531728702023247919663861' - ssz: '0xf54a912fce9636ed9aa1ec63734366696e010d14f2dead13fc8f35ad1d3ec7911fd3fd3fd6242389aee840114b414737a5' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '3226872671653206351676914632559409642389296844508917502616956261033920510952425684679204428343585652772222308348430668' - ssz: '0x4c890dbe7826e47328ed34fc4c0fd28e0a985db707e9979b8bed4ccb40321f197915d2c5e05a672b1b517dcf78306ae551' - tags: - - atomic - - uint - - random -- type: uint392 - valid: true - value: '1242606163273365581795881178398470490097374404781583102265390834703788683488007306443266184188594046238364408451688890' - ssz: '0xbae913c42e49089b30789d960ab5ba9b8ba9600c3b99c0df06607bf54e481a70ac3bb2c6868f9a4206debb36040a60891f' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '4247167969569434914428000905166769280195478770049766826066869811620360862761353851322147013504644438852087209147275790' - ssz: '0x0e9a784aa5992b934e329abdceaef3fd977262918fca6f16c1e97c264e5b695fbaf58cd8d62b9d8bd2aec5ced13868ca6b00' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '62897571922223237987948838179091913211911146453952313046870425004733169411395454895144015160838936819250700520783547911' - ssz: '0x070e3be239d1b9fcfb0ac89eb7a09b55c364d3a7742f4f4f2840f4e44dceea8b94cdbfca2a2ee7391665ad94e257c54d3c06' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '1551379147805009083156257178406025869454316064989258034685375266132065192447868085387068747648093849198696098386196354333' - ssz: '0x1dd5ec9255b9a0695079a25a2794251288142754f3b185f6ab46ab47114b9ed396503bc406a7915878c719d2faedb619cd99' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '43752006503828892431060792642033165147579025275413809148312827708285424801253085792607241656512905989463190310478149414' - ssz: '0x26f7679040cd2a26f2c2235a7e88d10907ee27b9c02db603261859d6425754a4068bd398291fbbe8c04c7dd14eb585665604' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '2346254434071671849097744428297383284411620331026052645007959273602011246585321440917194187680404027536760353313556637252' - ssz: '0x44a6956e1ff2c33bc02824d2e8323f6e1578fd91a7d80b772a1b3d4b68b00fd077a514012fe0ed2c755fa3b0d20fa9929ae8' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '1461491977998501580708730827034062501954980061179575335014489917569727768605498672936570013155259396184447460120582787843' - ssz: '0x0393dd2cc4dee7bbd2284a3881e7a1a6ea8c498c1de8851bb2cfa10772d2a6dda1e6770ac279fe64b2e2c6672be1fcd0e390' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '1158122924777378788731681281471678330391746679364789244646355039213337460515179704954753540732069853498248098333265716940' - ssz: '0xcc6653d04554d65ca09441eba911c70b7d0ab1a4f4dde89d43cf5986abca4b3ad34940374fe0548339aa4a667ced797cd072' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '677600784103219907814550219804169098151568238047606671117323984744678780539092251312768920803877918305050104115891226571' - ssz: '0xcb475f92f6b495ba9e9f0714e282508a350e6d1c16ad3d27a5e734e125e54b2ab92ea74d61653607f616b351f452211d2d43' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '2152365302791413768308561343990409587066352724717991811606790055842951739668344482280114092914107740334075035287413688638' - ssz: '0x3e89e1c97784ce5de23141233c98630b0101dc8351af56375ef21db78407db71b187c4aa0825f59c794c2245480f8ec761d5' - tags: - - atomic - - uint - - random -- type: uint400 - valid: true - value: '1470181807307583772686174482271588374569975040098975152461298637265339211365824569060435931932809610864400878831056976929' - ssz: '0x21fcdfd6d0d4a144f0b7f87d1699005f0b70c6d49254384b2bcee10e6bf5e2fe810bce43734176b228cd951ba1b6f25bc091' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '113461021609455118456917400365163393176461427732400393431188790564647687169891263568638752254673117879552813373462116697177' - ssz: '0x5904320b0703df88656f086fbad756afb189091c4b3602419b3ff5cd1c2a8eb5a64d743336f7dc827762f44caf6f89bc56f02b' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '161177877970261894328107020398331290218417800600090206817992474137761559884620792339285984023367490320384908621419860513373' - ssz: '0x5dd218e6213cddf73bc4c51a44220880f73ab4f928b8146c2fb791ace8b7878dc215595afb9df12da336bc25f54629cce86a3e' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '563852494485552482415660442562960508377551210793627899809416909836509534214990856044040238244900230349776503138740250338525' - ssz: '0xdde49bea076c56d938a51cec0445fb89432d8c94ffa592b09069943d3d4be313340b447a46d7fccccc455731f955b95b685bda' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '90091472700162216656495354660229654130227520267099510089187226229042295607434694474923734892617617710570926747629056641179' - ssz: '0x9b48c34ff034ef7ba3f21524216a8d48a207ae0bc0c12169a5baa1b0fb4dcbcc8155fb10ba98ad76401aec972360712d85e322' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '415809549226756195749155342966690336581194021631065106442409653768801095627371356147744819027751181798834614186798936025323' - ssz: '0xebe8d82f193dc0f851da765765166f2e979ac4c263e786a8a6090adee1519205c6f1b15590915a26b2ac541a02d66c83ac06a1' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '276023783823955506549393347863442878099170658215126189010103924230928794599111745180024727811897721625745210370555010521349' - ssz: '0x05993e7a78b0e2852b547f9d1a59b5b2e46f1cec9225f4ee03ed547e826555490d0bcc5546ad9de1bd57c29d653532178be46a' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '449895294533579025300404737316685596878938913462985420449139687421906568165000297009255278770830562333600128171028228901150' - ssz: '0x1e89940a56b846a22d74d2eca1946b678731494269442083cc09edb5e63f0e577a8c4238f3deb9fd50259a96cced71e7e039ae' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '50562471859891828436390960068990818307060336446601124150837221951715804359521554452732086632676134312448426585137357429157' - ssz: '0xa599a642197516b9364c61c8e5deabbeb8dd6cb3b573ffe6e84dff10aecfa9cd343932d428b53d736a8b89cc29989720ae9413' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '453838100169733997046000271605663109119214764159253951985475978133073155443412597985063120525637355141916869712230049925729' - ssz: '0x614ae0ab114ecb1851aa7270702238ef323174b5aa50f0473b3afafca72049c3acb1b35510fa1441f1a994715d309404c3c0af' - tags: - - atomic - - uint - - random -- type: uint408 - valid: true - value: '29099784399573265967434265629358336540859752395828923756099117475981010749749538971931403889578201951999416011583138884099' - ssz: '0x03ea0c6072438b33fb957504246bd064853500f7d68de3a0354ebe94b38ad7896f43e64eab1f8766235f34cbdd13549ae7440b' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '159331365604096661505620376840648156589121568178755563089267291599820898659180600810662108456164619166666128770642984882726469' - ssz: '0x45e6d46e4b094051fdeeeda408c921a27e3b36b26a98f9a03b07624950fa4e059952a110418ff975dd5c6846f346faa12b8906f1' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '17861206962090500043078253521678311806079514676484513709411126873582695935778716158996558404693291067192395720339474404900407' - ssz: '0x377ee4d3bdf9d5d77ddf8dc633b5c90cda36683e02b441211dffb5bd014a83367a4f87f630816b3b47892419553df323a4ea041b' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '66925896388801317513386317110251178735286908875646620681224985346300006022251502647937379454733944843202707819399103733333852' - ssz: '0x5c7fb8992b39438fd91b6f179e5308973a9f65d6d9dafdb97fc9bdcd492b679d6467066fc31402748cdd81a6fe6c2d7324ab3d65' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '126708894271250803276338248141968850405749862876738075440572262718925143562486036458850671891733994793814360836052252377427749' - ssz: '0x252fff1af10ca78e226a473274e22492667152ac6759f3aacfa348018259daefb1752feebdc0ae0484e7a004906b644f172fadbf' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '25988379260447854366815862554836026940884013638127238141531023079033086699026694595449262697206366046128024132033409578956422' - ssz: '0x86f6cfdbd6be8393c23a9ac655577e9a7cc8f4f0a60fd899080740c671545e4b06cc521b951f7b574d5987b1d4e056171e3d5027' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '120088987675348566515729404989827261775586059417498454226356407284305924914098494422138503160447710270254577847355714005384557' - ssz: '0x6d3dd474087e2343df6d57d0baad425917fb4147fe75ee9fb374afea9c0b5caf82d58cf2ab329dbf0a5f27c4978cb4387490a9b5' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '93547491052183338145599971805906377681735797342508503587174837164256802082087022002674715617504870509979774980751854459801182' - ssz: '0x5ece198de9ddd9f77f954f74d8da6a77b2bd5142d226cb7932720f184ab74115c279e8edeae7e3afabf352ffc047272c3120838d' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '164351983873113724076333047429017165244726364297738551879620927141923216081746747581145243619609348517814389591463518769192814' - ssz: '0x6e1f8bc6e80f4040940e345c63b455f7bfe3addcb69e1a55313f275cec20990e0ace4662c47398ab29b95957fcb38c2cffd09ef8' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '54128614234903382852871111974069705655757558498538078415502888538945782498787696738769046517897906323605727301475187474796373' - ssz: '0x558f23e2a02ae379c846580bfd64648a40081981dbed864db5c4b851c9aebdec0f6f27455aaf01c297cfcb9ec36b76a0aacde151' - tags: - - atomic - - uint - - random -- type: uint416 - valid: true - value: '104165421524991117164953390358022253147199975161028648181031904003838458174882580987349681429653037903261306529780647893961515' - ssz: '0x2b8b40fc82216ad1cff05a597f3d44d4c26612056128f2ce094fe772ad2dc0d44aa2519f3fb97d2cb71ae05ba49b21e65404939d' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '4169972146083962858994368355622153980043614666861543850625878741368389447260456844451108648964086323107997764532315255678801292' - ssz: '0x8c95d1b1afaab143cf43ba7df0c67700000d0c72df346328a798743e0542fb58cef17bf75ba0ba3bd2640f1daa53c7dfb30a0ca418' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '39771273993074588619004184460573629293748018167798881943436968176116557454686064571700949882485995151356699920555117287985245991' - ssz: '0x27ef49618d08f771bb85c3cadaf5fc6011cd85a55a3760ddb4694299496cdfd5e00f6509ac9d0d5360e78506e7819dad2f693f03eb' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '22855529001842080759396223578629577462665477539469606948724081840240495577255589228240180541495979751710423837630740767854211463' - ssz: '0x87b1a2f769f6024007e0523635a653b24407132d113b1877e1174a1a4de00fb29d4497c4e020eabcce6476661523dd8fa5ae450e87' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '5889558532175871569990532942888255735079398587019361339127059190885582497236914444258413506253897224960848316226216035011606564' - ssz: '0x2438cd1ab0581e2343def20ef587af021dcaf341c2cc506c60a7498619521ca9d57547c63010a1d3fdaebd9466feee48e5ac51cd22' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '11693859383588198827743922270431245149460223366994698644524524830783316631043965499931893591349451776400621246411167350591367408' - ssz: '0xf0a87457d20652a078852e46f486a03ab7d01c642fa76601a76b2f0f9159b8db5f3312e2a89730c447441caee59360f2bc87aa1945' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '27603421159757410541692309030777374639389468285518150598229786333384429097978523287400289536462210010452160772019672970543426274' - ssz: '0xe2ea7a260c127a36f7d60bd6c9183d866af77c2f9f7fac994dc28a2272ae61f0ac79a6d239b46d815a13a8c855a685ec7f8f8e1ca3' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '15983238058020606322841564303462271747324517492562431430205656490139062357908855836226083945968851195880612475787076340119161464' - ssz: '0x78caf69473ea2d9520f9408f8c3612a0dbefe39e129897180e63d09dfaeb5d2a7fc2905b27ca62417b7acc772d0b244300d957725e' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '7068857972143308191673151889969682971726414171708434124537299818725558714984213855108050683021328595535988801561565950755206936' - ssz: '0x18f71b65d6d7286b8850425c8f61ef18a32735519eb353269cfb6a421f920bdb7f0082ca5657e82d9d400e56a1309772173948c529' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '13572225941337295660648603746777467779188958394212015432660793630540183029609849134967837240138642924482648093669254478669901938' - ssz: '0x7270c95f1d3feecb86e6b25fcb7ea044694a8dde63c497a91c09115a26e2bfd1e5980026996bfd69d0e780f7f156f934a43e213350' - tags: - - atomic - - uint - - random -- type: uint424 - valid: true - value: '11738758844730304687783987959426666333306171641320675629640636876039084625352195450931619756138919353721685459275860112975699152' - ssz: '0xd09c09952f0fb1754a051cfec9e337983cfc496debc1aca868e4bccb44d32c96995a09b42abc853ed179eec3b22067005e42965d45' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '6419141289321281887213744774855624377406927509691556779950652633796989497534113999541941024240959610928817591591198692296687435260' - ssz: '0xfc3de507ee1aeb70a30dbf687d880af878960eeb92f54e919c3505cf3a87d2fa6ac83f18e61f51d795085e0dc99af8fee7ba69632b94' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '394349901397301538748345241928612753125986957854568694986997408377293145408674840181027039516959823981118209843764442835232133017' - ssz: '0x998f06520f14321f8f9004819042769f03ca03738eaebe285336429382502bdea35ad4633bb1513a9c58d3b7599b30202ffa67411a09' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '2995512148459941522251311973202846143976345727465277758032694728224667332643739910489824096762454862531605560802246226142960827594' - ssz: '0xca3ce0f312857ff47f3a15bdc0b7fb7a4943765c94d383e458edc8df219bc4d23d9e70ac16fd3878aa3edd9c61dcc8b725b2bccc2445' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '11062579283695749428688196400557325234013923757810274179671775813391360717205427888660599307532251145469821223829270398683112875235' - ssz: '0xe324e107341896bef61d69995e076f654ad94ca8dfe7f1d3ba886a6c020c50589708464f8b152cccf7347b242598454a582405f559ff' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '6487364518748342252851559755784609760039178228835556767863545066925442836662751281153225616913762734468708992451624420988764862862' - ssz: '0x8eb9cc2ed462207fedc730c3770c14f16005bc746daeaa098424a1bcfd7361e871fde3d4136af7bd7aa6f868619cd6330566d286be95' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '7699161498798831098348883188089734634665216560919475806638009621138740086461014305055176642365948430279919544882776201473115042640' - ssz: '0x5033b0b04d5d29ddf9ece26cf01a8f1ae39c214f00ff314574cebf2959a89226c0890bc1579295352814ad4e29af60210223f129b7b1' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '6357403771462204583172663975627499180128251857587769076147787071325328639978800600952927153554441733559607796208901478865049372985' - ssz: '0x39498a35fbf684df8916b293ac20cd97b34695ccdb4dc028d97d5b0feecfd01a28f2612055e27bff767542eff13a9c40ce7a2493be92' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '7574416043804217061246750748978737513926323945055065325131704218046097685903291608147003087069031306333161650486221114803354824922' - ssz: '0xda70a38fe7894d86809927a0b99dba424586c1d93556901bf4faf9f5bf79018efeab03f052f0b08ecc041dcfacdc7b0e18189907d6ae' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '9357324492136846288323549114756479335338611150748554490901975855172689085450148877520953773076721042245817816806053977249504685804' - ssz: '0xecee85badd3d956c1b3e7f9bbd4ce17b2f9e71cb2f654f51146dd8e3c2685eab17635d962de21fcd14eb983ac3e98b1e7d49dd6cfdd7' - tags: - - atomic - - uint - - random -- type: uint432 - valid: true - value: '2329812730267966243103926754004352213819432007317133515881600370908692568424564008210556271375209377960488777918427266565607814702' - ssz: '0x2e76ac97ebc6d9f9c3a95eeb4cc35fd58c52fad7cfd0cdce16f4a697ae06266690a6008a7e3d84f1f6cbb4e9f27d99b6203c721cc735' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '514028040159763231446008961516794474888916955062297565220382741839411327721918349021425204704594994763163043384860537036290813425987' - ssz: '0x43795d08d04700a32e75bd5ac51b3335b9025be194ff656942adf291038bd4b10f264ba529f4a81d5a5d5d69bc2a0a359edaa05606592e' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '1223041147920691418507535705620177978744499694522727552210745007411233451392996471437448063365143287067418850088121530744795381886290' - ssz: '0x52ed631aeb1b1befc315c1b9315642c10e0392c8ab5f2e2373baf845605a533c0fd995ec8ed742a846c73dbc30b944f9e291d02bc8466e' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '2454236307724703159363090145682800611466361635575839954993043564401988584381181180804873328972181786205585351981099818134684809856957' - ssz: '0xbd87504078da6382f8b9c43bec32b07fec4648941e7b483651e9ee90c286180df389f0901608cce7ef2d39a9a09ab11bd26ef243c749dd' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '1365846486265995352980912539505908724029386421876495783801253316968295182495585490344828427768192412612118460554170221555434734135992' - ssz: '0xb8aa0aa428b8f81958d82dc88ce99509c4599419887dec53c328a4543272501d35e61b9f0bd87348d7b3b2f780a727fe86e70b1914277b' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '740757568295914766229320438308609164752588150569210023992744195480708963260348134261869507339432213055674524636416409384998365053073' - ssz: '0x9140ecdfe79eb2c9834c924dc875f7c972df0f92975b9d1069a5c218ba873d64c404ed7a65b93026545c0ce8b6321d53c09e98397fca42' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '1405439067384555941836050901147193351471391586156867176239384030523392628274089342336242878463740926408410482173184796184887331552944' - ssz: '0xb07eee3cfe854e23ceb2220ae4d1e2b638bbfd914638df0d1e61b9775cee037a72530f8c42d5408de163313cecf19f6c04ae74def8b87e' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '2294004515487741116319256992682205248271301161766838034690043073659296049906865039006207368495301155029418499416905998556115393759302' - ssz: '0x46c8da79ae2809433c662cc9593f9f7a8d06cc3040b30dce5063e47397e248ab27f6e428d9c34a9ab23bc836654613d5bd90ea913cd7ce' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '1202281107898550907621450090974404155939235407732316707421611751680840802831028389407295173942147933115721736254312799330182913302885' - ssz: '0x65a16be76cf76358c926a6ae05c5f9db7647da90a52cca46de0de50182403a4e8b4631729d6790ded52117f8740bdcfaa16636e396676c' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '143618629713062870398677277011908835375718070041707189232511397158188991030570818590933871208872412848165230586453178547410074176656' - ssz: '0x908c3d650fba8839dfd0124adf134e94dfbf9d501e1540069b5d3e5cb076a7d096bcf20823012b6d643a6dedf3262bbbc2da78c011f30c' - tags: - - atomic - - uint - - random -- type: uint440 - valid: true - value: '2572549636006584246982474898308621947242755229347359606746830648735007257189348753989006788433009231509140599186878448662668472195930' - ssz: '0x5a9b7b92671e69cba50503a050ea638cc60d7bca993e9d05a46cc8bf77075a0c4403aa0dc8da31688c1c93f4f5e58a9ff6c3fe4cbdf4e7' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '246416201043726844179360088388913106752351070750163253768160828524971144388163443923241139931618685221641028950253981348946657142937100' - ssz: '0x0c96e45499dacba41312b906852d80e6b824498e446bc961d08c2d1bcd39b66b529b004693678ecb9f1f88bcb2672d0b6b12d6ccc950ca56' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '203238052207924696038662662926765236458869625942995113634860677945587164059881291302030357450133391194754409352096720566440927423903545' - ssz: '0x39379886009661a11bda2619cad292d5245fa592c3951ec17bc1688aa69fcf089d3856366b9d919740c4b994737570691748f5d3791f9547' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '290835705525559513971591750730164868873851068070637928050616258363476796876092010208611194666447682367072950635429024346123593471071867' - ssz: '0x7b96b91bccd5402e2e6b201f8a70e4dcba5dce271000fd8d7917363ded0a3a3b7ca1aa7b4a5d0beb702dd09a4dc3f1e9b6e58942a06f6f66' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '333064016894712497211605312537942543628764109637296170575276279231175469303446716282928246088070914695409501725469954449726202367475713' - ssz: '0x0180140d493aa585ae36ab876fa3ef7c8ab4d7d96f9e3d130ea529df89b87f3a294d4c217337d1647c0ceab051c028ef4109caa85dfc4e75' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '587863929699460423873263263891916233817469707284519723944507640760086410277566100962792784638218176032842415697579742801900792069767040' - ssz: '0x803f24313177a58c16827409fca96b8dee64c2fe50b484b2e1c607aa5f2bf7638c52b927545e56b3b7c0437ec3c3d8bdb4d8a792bb390dcf' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '154694451161940560918503233491504843951427272187380390343486310805307940798605991304788607867244826081313066644123523273188387890838976' - ssz: '0xc0bd2a352ccdd9d7f96270188feaa34da8c99d4cf4f4f13100cb001ab1a4143eed0c9a68ffe25ff1d377af883acaf129de5fd25066267c36' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '691375110132974598504225219123973274349648387306452387169800815471501259742819708149917824838111826897187171188177185115823130182242455' - ssz: '0x97502dcba0acfe769e5af6ddb51912d90a2faa3e5d9b4a4667b7d3852d1732f0a71a535d78337864b16ef8dc05cbf010e170d595056582f3' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '283648559621493816014182606703947344423604196695247695245677751798657574018530537832607378701279968698541634970789664632873697247751645' - ssz: '0xddeda3709f42fdada807c4183f4522fc45aca82aa38785a3610fd91e63d6e2cebcc92a863456bbcf486c4344cdc1d343fc2c3502b766e763' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '276066325033764025582517737651018859959942449495651174100203565966864769029923001646110420858273441743057554012471310506061269236814653' - ssz: '0x3d93e932d4135a06429f979a179eaf297b7266c9b04e780f54147b6a26c5f16ce529485559c524e51a2b4d6d69f7e7cd07dab7b830be3b61' - tags: - - atomic - - uint - - random -- type: uint448 - valid: true - value: '670650493194601646392320947758429870193538980338118199206960402816594957375145476361952460634220584266899935440032884114961997603845875' - ssz: '0xf3b6288fd011913c4c21082a80894ce61e6a01dcdaf89cb9db890a55e74adb6c4519c623f2db7181183eb84a644606ef513538c028be35ec' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '102805373965532814961848807291887401323266174721315483175153020984939115384449127712680563054413656391135331963349759230349825991858984297' - ssz: '0x69152c3f9ac24aa3351e1e13bc73f7448f5ba62578c4c89ea97b8f316722163f86d26e220e18640303791ee5d40491b756a819070b7d19718d' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '93292933700035973057025919159872975181785791189089668247770105558051769978661384826926704767245423368347045894238500216048931070069520395' - ssz: '0x0b38d9b4711f11f5537bdeccafadd8996c50dc957e43f2d536fd62cd94fb7b2f5f2e811baee3827501ded8c624e6dd059a68607a1ba3b85a80' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '123217040389821248420066541897137003194126917464485728822383049407252737026851919256356837770845987625458167149375848383259229504386447456' - ssz: '0x6038dddbe27e2aabb82648c17dc39b5eb0b9eecf2a9bfb41c4806e74c1f1d2cf2c5c23f477c990b97c4a839c5a993b48a4d86d472adc4b86a9' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '61166052648956027090477675109934491936979740066040487029906659807540105604405349067742544547305209757914535746389516307438915283945950363' - ssz: '0x9b8c82fe0785d95f800acafaac187721f2751411fd8aa9a4bd88e370b14266898566171d3667d5d215daa0bb9ef5ed186cb9bbfc9a7c4e2754' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '156786905992872955803308946221010293781630556189028131258694176331573617228904165678711428643524244006354784629777424126882482807151942467' - ssz: '0x435be6cd104227e472bc7deef2792b101e5f09f132ab02a8d914a76b968f49a9979772fe3d149feeafb0711c7f5c6293787279d373e0f1b5d7' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '165152306884598897566960841058103380516641725767185106008038917877347341378194960367629183543310546070109416303307480669655907978384395233' - ssz: '0xe14b4650abe3f5e9bb96f1ccd65e6f98b92d423082636e8f4b047caaf5a0c1cbd40288ab6fecbea8f7a493efb19e480b7d6355d55bff5238e3' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '76722058929635132509803636424762206912328360560732504738234294930434941182241475266925847761476489576876295497605304858794779612347722831' - ssz: '0x4f6cddbc6bf22fb910a915a1bb34cd81811c8a685c47ee22a78ac78dd4d6348a7a42b808b0ce28b81e146032ba2064ed0b92a34806584a8e69' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '76923234647682726111306022868346799722488777891421712719980026091614783268949710619949155870151982396826301134767531006533819039280770889' - ssz: '0x49afe34381e91e0e47eb718361cfcf5dccdff2b1037d04bb1142d448a20053622237a421e6036b0995ef6231362ee69fd346eb4cc88325d569' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '135993888696959055873315263004524900769614866593086427350967815854690252359549596121450912224739835471819924127640787635022775607050882300' - ssz: '0xfcccbb72ed315c4b0b87d200bb56cb0aaed79e6dfadab36f3e31ec8c1ea1fcb0de9454f27c88a50270125ab1ae92a02a25150dad38b26e1abb' - tags: - - atomic - - uint - - random -- type: uint456 - valid: true - value: '80190353610246172908070789426813428389101281816176242368260004540251733021929214362739438016970664569360108193884296208835005749645418828' - ssz: '0x4c21466bfd6d033bcaa0d8df6407fac3cac3cf44db13e8c462d6cd66f7bf1a80d970a95ad568be904f33ba2749684fb914f05c1797eedb536e' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '22530369699872541951983379827836173557738664740144876527285282091069420689946938368032416095050156967430271266810807054801635812166053026755' - ssz: '0xc35b1aaad09cbd0ab4b7d9f89749b36478adf0df7efe7ec28c802d60ad5749475cef535421103bfd43ccfd315d710c8118551bb753d0a1c11579' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '22057702698962344137657465103631616018131081846277651019752523102033344923103885615101889372708730290217648509174578274765702675829377996861' - ssz: '0x3d186891212c0496fecc5791c1f05709f50d16c88214c07da03cd1c8aa7b373f030d913428e5ed471dbc22291e9e69decda8252f7c5280738b76' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '33222118688602071687800017999568596461949609937051308025022858977210821091535260999896132588968447042264371681774887670379746661724453459072' - ssz: '0x80d439e457e1f94ec58be3a7bd2d650b04db3e9100cd3b3414134e4cce18777cf644d9615935e41c8b30fc9cae1b79ac039484cd81a37fb08bb2' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '18183220739516959424947926127609785228682685342499985336469655540887468386736226582060797374380560706640327734356825257558558772366562490022' - ssz: '0xa6f6da16a57a75aad7b63275f3e11e5dcdad4f391a1e789e2c07ed94a61c570bb73370cbe6bfe319d6ecb05be3c7ada87ac40876187680dbb861' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '19472369425114632925711799596229169565118705096519535271191939324591247184726117548427876139732417580214545740439513572615599557945162813185' - ssz: '0x014f6d4fe72d084ac99596bd8d905f19c628a4c54381c00081d86c11ea9890dbb492acab27224c9a87be666f5e921bdf77e65b3345cdcb7ea668' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '43327964681457755689063488002775650902577187652911242693539957215606615748046658003692643741233262269827263707877541977764429895382173823902' - ssz: '0x9e331d7d19694fd2d739d78eaa7d52adea828aba7150c467d342eb8446f007792ff81ff1767d3729ab2382278d743bfdfe331e0130205d86dbe8' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '39869270849136708682000722974167333126355787724829411072096681103986697311550673574444764733874702123010718522584269952949547722426613669193' - ssz: '0x499d8677eafa20af220fe28d4b1ade5d2872acef010bd67a45e28b9e088ce511af80e8a6b0f9e74eef0ee735e862a5c0f8dbd1ebf7352dfb44d6' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '19929601954653473377264309340216604190747950876252034197030884047888769744160837244429168563416357230851658955981036546906027249767121113402' - ssz: '0x3a519f76e8370b5a67c4457118df56a59c0c0d2538ab3cc70a6981b056c3507bafd875e3494d725caf347a1054c9d141dc49d6a5bdbabf901b6b' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '22782190727475881582052679139130903855006389081453159314873822616964329831993630211649773612694835415310499902624990129417220501527541788396' - ssz: '0xec2e130c779e27114c2fda040d1a604093f049f3f87343254f6a0e70b0c815c3ec955afd8777bdfa30649828375355e4586f50d0c0f08f37707a' - tags: - - atomic - - uint - - random -- type: uint464 - valid: true - value: '5879450681903931088511428832977637272445476307243582435715679989493617189235593649143888053618489046584326522905895427095220289897666648652' - ssz: '0x4c1a03a42c4a0a38770951e8079e1f8a70be7ca848c395049748bc0fc3c036cdeeeef572b771127d898ef7546919ce2646a55fa5dc5b6612991f' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '1348423945226775034482437413124154910811249547380974430909856651908475203882614275316442281870487431049329860901475278114608243740196287390750' - ssz: '0x1ea4f107601dc390c93d9e456e255eee6e2fcba8fbb028bfc48a9c9292e017fa61c987bbc7cc1cf0c7d1bb50a59a663c15069ec0be1c5504d64e1c' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '6518465420646570851319774511348748454110212425327691151679507919415440571598786403062478744755042414708135441036466084580259433824165658625927' - ssz: '0x8707bc9948d6dbf9d2e4d0bad7d04fae8eb8fdbdc9b0571c2131ade40c3e8f22eff95f8b64ae331e3828cc5e40b49f5c72aab9ebb9cdd3c931d888' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '3361355086817535935829925085552097133379157271261909894202170974925724175979785331515809738185808804482899087279471352939689933117924005496134' - ssz: '0x46c5e9eac9ab985deb5bd10d24ef0a10232d9f68026f944aa73314f1ce1441fe3e6b94cce05dc05cc7d7a147f6af22de0f56bce50f4dd001ef9046' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '5691196358964131645868088435747619729562995783219308192370687514465361673305451276928613406393932060069366131310402682552122973610244760472287' - ssz: '0xdf0a497d7c63e05521e172386e59583440606213c38e966c82d2e358760bae88db0b40a99171ad123b63692976900c2d2a6528a3a6af549e337a77' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '11264282136275188428637407426838650698968225727234105441940491049964411494641218050633043370397907617375623307957515453883327751093896124334297' - ssz: '0xd98010d7088ba28dc104bb16703e5249195bdcf4c365a4b422f23480f19bf9c2de3759c6bd530161d449fa0ed17747a00862785b9c501937a479ec' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '10127278323209520760618415692176687361921453917667723833039120912969982985704121542925839769041515694394005556415953454813280172573508413651471' - ssz: '0x0f7a23108139f0e7487a05d9a0758e1a1f6e51c992fde69a0e146f8c885d469ed4fde30b18ed675de5b41f274a00052a062e905b364c2d760a9bd4' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '5049951315819495231469201624332535789081264521930316474066240286348981891890626959220851345285427215013974931424473030642099020480324250088606' - ssz: '0x9eb4bba28a39a7f903f9f18c3f04c4dfb5df83a36b53919ca3edff3a4a7e3904cf4f78743d71da79f465ca10d920c03c459d7713dade6b34f5036a' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '11856436373188990359378342622092450699980949034853004167647193219431513982895875100334215768933420778611170982543222474803906067314242414078078' - ssz: '0x7e68322591cef7a8a20ca7748b9acc79500a02ff934068897d14b4abef5015a543e96c505247710375b3ed5fe197ee0592a0141584292b770ee8f8' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '11624443541778448095201055540686355063202164440895564587397790162680550399601284757045166765063481425700986932891989889814975229337927085799044' - ssz: '0x843615b5da03c601b01274f3f1c25b3f06aec28640c7eb0ef54d8dac93acdc1ba295c2eb6318f76028be78191020e76847d49f20bfe497d94109f4' - tags: - - atomic - - uint - - random -- type: uint472 - valid: true - value: '4051271073476725797622978502580490399792635236384486294639472893911851465414466561981774204901299221620286679894605056893749825911397358473875' - ssz: '0x93923393410a3491937a1feac1f1ca4d541f9392ee2fe3627c1c6e01988d9cde72726bdc32bd028813f81508e1a1b892ec488f372f85a3edbf0c55' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '2749638391693814824462311603702485840159383794814334155854492090616052398475848491515735919082904993175388380094061496211224045251435047406893356' - ssz: '0x2c795998a99f6d2d30fb48765716dafb27caa02d4809df730417ea30d4c2d3027a8e5c81ead958c4aaa9990b400a22ee25925182e2137d780b287ce1' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '2188036895666390011590815152270174004281814405156934323883206264124592106292055896950651402980698740463874030155366525986375852261406215276736480' - ssz: '0xe02fd6f24eab1e338a9179f96eeb1f9100595bc7a2d2b355f660c2e0f911bd314dc621b1ca60fb274c1312c9d37e544bef1696888da87e89a0406eb3' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '1317918658680722708835329426976296679006905606319693175050382782786544849356616512385175534937192669906925873432793677418374407122828867874542092' - ssz: '0x0c528f6589113726fda9b3c5c74f95ce8b7d13ad373baaf2be9792da8f5b4269c4f0ecce6f08038908e3657d499a80e2a303bc1a1ea5a1436a8b136c' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '22081782927218928125778779369550968535346714780662978818755333001007975249647342594027742408251774350847450613481239737506645867036514161197899' - ssz: '0x4b0313ca891953da676cf75dd88feae5a39fadd7f2b5b2c4c6d62c667c0d0f5b133863d1ec4468f8845355c2920c57691da2ecab313cdb422592cf01' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '3073958132599819962582914814120619953553652435422800625279463967838384448155953345971195861517445485622160015271136469798768477896310476926445506' - ssz: '0xc267fdec440e24757bfff05decebfe36661bac17a2d815515c5e3f03ff950d60f7b864dc154216ecb4b9226b6b1f11344ca223961040d46ceab714fc' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '930117232314538608814586452703854362641400484336450837205570712712650153539412263812152601598794563702835367499133979505777862606271482636869163' - ssz: '0x2b1e5def808383a613b33da17c79abe4057144bb6c4631b24199b4a495efb8aade66586bcffb77512ed1b11dfc2e50040fc00035f5f090a2dd49464c' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '9525113958011702260365319632479238019253170676743842331215206589878259120785368912303378704294319450776010398841072964634690364147683501832919' - ssz: '0xd77ab0d051f5bffa519a0528e3bf8a3d79ac26a64753508580077e7e074ac9015e6b7fc0a0d9a2210877637c062424a4a7f70f9f4368fe10d4f6c700' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '3089869664575579896881292687382493530745729278054430855563647589381778126889873267222430969263701364006458815325664744411484027417041541587571290' - ssz: '0x5a92f4d7d9ca7a7191a182b915e4864453b89032ef02ce83f9d842f23fb10c8bd98e60fd1c11ef23a30edba033980dd973b400d6cd65baaf46c162fd' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '2676630200424584735522771830162664683378598553860255551969711166687239609709162210628081837545410742357465150754036397513047374917086141553499324' - ssz: '0xbcdc3274af1b9535f183994388e6bdc39e61636b32e8fea6a1acfef507460bd0251df46f9392927d0c4cca0fe3f4bd57f0388ae44234a9ca0e787fdb' - tags: - - atomic - - uint - - random -- type: uint480 - valid: true - value: '348089219201642602859222519120059062451065537871706874544845393900787393768103175851566160496785297069372687174861800607487439864891252373292477' - ssz: '0xbd85e988dcec844867e74da632e307e12c45af4b2b4ba59f1f06b66f012c24d8943c61576756abe21259aba75ba58fa5cd6f81744ba588fd32908b1c' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '37147144462198307272012116417366048679122614032307038258777683417167803815859754405546623683318694085241108779205492759561913426551294535309477623' - ssz: '0xf746c4ad4f13687227dd39f90c1069a50e40936976b1e08b05076e08a94df665d678ab8a09b8f659179339a3825fa901c1d4b55a083d3cc6657b43e60b' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '82226115669998822836719969198820426598888673144332716434284929874435450310546629649031939739249831974452600516866771362601061262900544854224839034' - ssz: '0x7aa1d8315b5de59a96c0cc89a00422e0b426ab37467064af7e36621d84026781f93fa767baef341e94f49a8c1136bf0d99e4294327ba98514daefa561a' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '400852819349924830094471586988724509084678818404051034344371034961042390911732219476908123880791718186697115634180997744525639035259012174046506506' - ssz: '0x0a2e9773724379af1e33b2bad58ed1c5ce703d2641d8258205309e962c83a5047c2b0999b354c7a670eb52f953b0d6ccf3f4009b8053199c35ae106880' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '786498151876341735250524189249312157539439888501900344959834142236046919346680403575612914762547920276695371274534301509838548456211941505773846101' - ssz: '0x55be6f7b1fe8ba4563730c9d52e709bcbc71488822ed6bea70df8face00a1b39dec7314bba578229e4b51e3f859be8ec681b6cfaf4127c33821209f1fb' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '100361271215266487034245481073609753601391531014004209741577374303320717344268986947987450522592817741548471525770922932342212457886889818746040920' - ssz: '0x58b248bd69ca233e0ac347fbe8fa6a3ec4c54dfe8a033ec45d555045a95554d1d41a7258505a3b302a73dcebe2b44a9239d07fb7590d7153d194282620' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '482901758660725195390213085240475183072278084516918153178638010667860001221845126063047657826974795076709961661517576987286161447668587449312769945' - ssz: '0x9977cec93e7f6a628204923137f6fac24bb19e346a4830d4cca91e9d9b18849af5e266351c73b6d5e4c49961aa6be1dd10bbc929ce74727c72d583b09a' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '720960038680116811970143838090487314496440388991549358072696184028184865366572584808545200280273699788643128582280650623819887406899373962675644023' - ssz: '0x77667c9de5735d14c8f43be82d486cbe594c711838c168c460dd72fcf8a3cfb6012bc74efb9beb37aff16e0772d9f50d418868592d015416b0ae8ff2e6' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '520166226244534434753310198374347434264060199793196460401679664541902691950997853917462599342312745238077811640319690716407214526018479199502540945' - ssz: '0x91204d4ac07dd24f15340c7eba11726061158046f91af7384b6c38ad906b358f6d0e235f9063f6879d73b8ecab57d69b1b33f41bc03ef6e7995266a0a6' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '614610537810329639884486046732207318214370077413904256583811823807862498401220699415400304723389407939636667114451262455462166532506545631284367714' - ssz: '0x6211cbfc4b1e8a64b57b815e95c5461e6c78fb8873eeb8fab6b900c6fde1fce4219b462559fafd9e960f9f798380219c70f5d7dae8a31996ee0556e1c4' - tags: - - atomic - - uint - - random -- type: uint488 - valid: true - value: '342295295609394523042250426329392128078505988690535537334313556248009687717825982198850178469136590732796770102896744784058633910046749254227791274' - ssz: '0xaa0ddb6c9a70d3962cde6d8d1bc7138f8fb17b3eb8ecf71a66002cfa4cc98f1449ed35dcdae365fd59184556828c406a46352a884720764e7c5609a66d' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '149032207128341879543864880133276380098995601337726506551449979703616934716915346164554061563540996643968533058639883944310369514829776440517473253130' - ssz: '0x0ab74a7e17593f7664312f2ceca284a1c00bcfa47f4943e50fabc3aa4217699534624396e7716f49da525f850f477d8a76f00c78c524e2c961845efa7bba' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '184801130946020455460243220257467380422812018701051803876761587979412282556133070256983612515158281586264997579689789060392578063433905071596766425940' - ssz: '0x54f312197457c0d5d5cba3e220830fb99fa579002d982d570a8735c2eeb6ed5832c696750f4fa826010c3f8884ac1a46c808190d14e10d10eb7a8af43de7' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '98583807830140083736416774169197805374333098226401877256840245391472432637346446543395217225254337218664012930050849759243719057707539490237207026522' - ssz: '0x5a1b502ebe7fd5cbc1fe9cd35c5b6a7e2b1df4fe5edca8a75ddf11e3822d2b4d471bffa2234a9982cd75f926e94dfa2837f6ac97523b0512118c0fad5b7b' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '92707658340718799162754001854137238543516939578100575652576282221705140599271230821050767918413308324333194365145312580010707559670345373129381698179' - ssz: '0x83dadaed66e640800646a5afac4cc5b5d66564298c57d075f073ba097ac5fb1edad7bbce08085c84af77335acabf69c0a0b9f755c14e736d7c3c85590174' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '74293755296208201697672135615748571510821142082680496888814805623776538631438017122657707439361011875443922958437883036002814014189737748611466189790' - ssz: '0xdedb8e8fb7bb17b82b8e8a4ca989f0dd1204b3e698cdb3e9e61e4b1a86c8229d2b03fdc9649a195f757ca50a3894bde8dc17c0c685dafb95aa6471c3f65c' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '42724748555787501082144179532637671412782900992539413758464884323267459090673863948204661983391591179366026700270556892894469527368891604090404675300' - ssz: '0xe41efb50a124366e78b1b86ddc925d7a47a6c6307af2df2887a2ef7a768f060daa44e4c6cb5f2431e2ebea0ad51fd67ecca9f9d8c7765400ca83d4287635' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '154583248036438390517604284230716284868581384983332469373203394640206777690203138031409474801902640981271526900965681829174005866538680573921517177114' - ssz: '0x1a09d529cefff384bce33a36815c4aae17c69fbd16cbb21c7f50bdafc8f1141f60ea0ad92d589b6d7a19633071794187cfeb7be7bef17f05496b46296ec1' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '43069282347078261932658448546005549266888730458828445446653613148980681209038476687579970019643982782196527242819615478848171467457776340501601685927' - ssz: '0xa7911b2952627c1ee092c06b02feb5dc03eedc550a3f67836a6785c2247ab0397eadf2acd7200375fe64450fde3c791c9e001b1cacabfa3299676f86e435' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '61239447140501560559568031085344016814621494220202567689455820528615104462706190982853299717804839549228858732582858841182178051944570001996190001160' - ssz: '0x0828cb64a75d73796cbb1061a3e6790f16e5d3963cee9e2ec99ef09b8cf485ca6e59e9044b70134873e930194447a4d22dd22e0c863caa6da2b4ad08a14c' - tags: - - atomic - - uint - - random -- type: uint496 - valid: true - value: '112277454660197498060733520259851955856213874935591380356398822859775137733446948441068473558011201814988628102400680752051410131207326812492009133342' - ssz: '0x1e55193622fd86e9fbb40de90fd83a4e57639b137c9e6aaa66f37b31eac80a059d7ca293ecf72d734d43ed60a94fe86f85d16faac4ea2779260000357e8c' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '5056907309888320541161815051790306774311625192505776597574984312962064700149114942032106078409202083025036230097613740448507193542866612456855455986967' - ssz: '0x17f5bc4d5bd135f84e3af3340c1618222ee3f5f00c6dca1bce678cafff44483e89413aecd89cbfe8a58fa3a36887e9355ca94a4fe0b1b540164041c8b7b718' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '21042663561824662907439863652943367536165454361227350243723294067906748831180843949364446430411035615231220267815497384645056770973369755976079517873858' - ssz: '0xc2f69edd1480621bcfaad6d030f0f325c17a4b8b8ca21ffbadb0cd7f5d142ce2278bcbd1733a5b4360c4e2b48a747b2244236d15ca9d821c955b58c2b9da66' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '37970130004697840636168102047147344344965799417923432677013653413865330421018278457881008275837068147559371248744648078028415696444816652118647055357458' - ssz: '0x129664d13c1a659efb8e4c81f8f4973fbd43dd383f12a521bdcae373a1928932274a3b7fce3c80df6f974ed39259999fe5f0e17ecf084e1aaf4c5cdd1898b9' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '40874613696515365148716271461247932926896313675076421717941775023457279241892706142151987988710094882907879115076033339986649985394503582973858745783528' - ssz: '0xe8949d6c6a0b688ba9c2772d5c8359002e56ec680c0912a5812fa0cca11630921e7b0c9c3532b920866ac7e9e712a09737fd92b5dcae9c210b4c56b27bcac7' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '30354104768280132924093255160372981196521082872129827955524726394419053838597189907332671323192665866803620188124783928453933041650325553568750549854088' - ssz: '0x88e77bd40e6212ca67f9bd9bda3da77603251c0602ff2d88260320d49aff7aac2faba1f93dad9f9b834dc4bb1e58ca7c1caf71ba349658d6e0ed7667265e94' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '28077175127124308678119511756497846614106656294806232232843543790632539151716475544645338153291086144668863756674565404427528096670779197643383587161792' - ssz: '0xc046f7dab23f9f9c07a5a306566f163d5cff1e5b3ff1b35940602dd4a9b4425206e0b02bab746d6be8edb330980e2065aefc7e0d181b5ace43c47907063d89' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '30618930765723730149522908761683872819434963136264791261235711277837009210987811748318013991497422347919895928654721964552171582610563222600246935084678' - ssz: '0x86dea65d11eb94935ad23b4c25c478fa339505e523c477cb7697b8900d97554167c8bf3b50d76ab36d5b9b4ed70a1255ebf94b86062221d00cb513fd86a995' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '14933412844657125324483197859541509614180769461727386014505154243757808743022307058224926306256690056842436966222763777055669237807380208196331619725877' - ssz: '0x35b28b3d69dcfdf5e01eff3f4719dff6e4e2bf97a6230a3a0e5492ad4a3ddc08ed9495489508171c9d3cd66243463f56c92544f7a800906a0fde755835fe48' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '8494331617577107332723953462470964595188709870770205104337501379022997913356223412681967596161931317955400706143943274997555810254449195226131467214764' - ssz: '0xac1f1ef4e6e34e547a0b704210bcf798f54041214f2265bb9c66d3b4c569224c51434009fa2be3f57c150632f0d21c868596d94af76ae9425c5ae23cf98429' - tags: - - atomic - - uint - - random -- type: uint504 - valid: true - value: '38025445379213196192441073760724476757579482537048976383029657271979426909438610100300717108728023396846821482030981442243685594329410646464875931416654' - ssz: '0x4eb87075ad5d021d5262cef38a2f19886ab8af7cb1525bbf96fb2a52fc6dfedef7e8212ea1414b4e1f24d8800821a91a3e5bdd00054d1334f3ea8b3850ddb9' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '9128966724462148518234911578146712917885254463606709989283820697984291209122779459914313261910141263733600212783359304909160449079766870350194738827336267' - ssz: '0x4b9a9b096f2a8cfd1e65fea7780e327f2e508398cc71d3e26c81ac4fecba97dcb00cfc8d201edde048fd173d9da6bbadf0f475b78405fbef70abb3e2b8754dae' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '2766493950336444940710198980720847972398247314814001557983040377911846407275289453022892808844897125103573580120474388753772450362650204185003538705554409' - ssz: '0xe91bac1e7622e9cc6bdaca359a1aced547087b38a4804a27223dab27af3a9947dcc11084e63c1e7add0e5a4eccec67729af7864befc051318b0cdb573b57d234' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '4115497952546647476925661252772119087826261280445661968791027020780012609088575278269127153744344466291693363215646759538448493614234729178659813481683159' - ssz: '0xd7983a763b366d7a101b4dc963fc68e3e522d129ca201583e629fa385ec945c3f43f326ea281a063d838f24619cbc7fd6df0c937b75a2459637c10a68c22944e' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '9980292414604113787835342279115433183869356064133943161011616742251271867484413736390613023110859809498132705823235131692389778905240671729564373841263480' - ssz: '0x78bbb2ad25ebe421b69011b38bb9b76eb544756032d9ec7248b0ae6806cb79baf9fe0236b6f2aae42094769d53f6080d47326a4120f9b3915b54a78534a78ebe' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '2359155039914936175730764276861405682146165312860612480423599749208228272468929866423237102526476077993123511550869260701553361110369890721289717709028546' - ssz: '0xc23c78a81bb24a7b64919b93fa8770ddc3800a0c42c89b699202379fb753ee98f587baef83f6952ce36e1c07f87ce903cf30d298666a844011798be4434f0b2d' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '10071369062717600164754620904004132800619221282325932350295267058726514987118905090611714500666886435230489613485002281471395048914802470526934749916800920' - ssz: '0x98a771d1508526082cfad345a6c11655d55c5ff7dc27b8057ac15db59ce79a4cdb05ead8126c426429cf441a3ce81061898329685db3b7bc98d8a95497d34bc0' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '194916717751881780418206535424259636474087919265866157859073744525550156034340900097028049128885941733289809476824148046775698382732355556278649446538370' - ssz: '0x821c913f40872fa7e886128032c048579709d4c43532e5ad3fae0a69def06bee0e589592b57edb559f25bdc4c1174f11639930e012d5ff5c8e23247eaabbb803' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '5291662429160726864623853923064738605475161405731312661826007366085264849741156990967632894508842548406027420568664280371426629180289490610520820067973419' - ssz: '0x2bb929f4399b5bc1eb351f3c51b20a97244ca00b64198afa7bbb59d89ae8b58387efffaa31c6e53125ff5b8b4e251b7d9edf19d6399a775f72f7922c6f1b0965' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '6163617280699666745812376347703701577172141970886977214416727712934915022377539657382096100283043276169738730392227844543672055220386490836722703347482019' - ssz: '0xa3fd2fdbbf217ebb44f4ba45aa62ea5037a402162c3ffb18fb2104c4fcc08a2628f5c7a47267b4d5cd3afd39f3a8b77e5ed18888ad140d2e34c10a0f3a22af75' - tags: - - atomic - - uint - - random -- type: uint512 - valid: true - value: '8580164595911285878194311207791930585109680382258760154696139588823485283878156291631618476199413075350727786008847908978387989012980548631310633718461755' - ssz: '0x3b354754ba69a090d660ff5534fbb352269adc15465a734d9296afa25597ac6723813ae3c103e9129fa398b06ba9cac7fb57707d94c314ebb289359e8ef8d2a3' - tags: - - atomic - - uint - - random diff --git a/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml b/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml deleted file mode 100644 index 30c062704..000000000 --- a/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml +++ /dev/null @@ -1,6640 +0,0 @@ -title: UInt Wrong Length -summary: Serialized integers that are too short or too long -fork: phase0-0.2.0 -test_cases: -- type: uint8 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint8 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint8 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint8 - valid: false - ssz: '0xb3dc' - tags: - - atomic - - uint - - wrong_length -- type: uint8 - valid: false - ssz: '0x303d' - tags: - - atomic - - uint - - wrong_length -- type: uint8 - valid: false - ssz: '0x084e' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0xbb' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0x7b' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0x0c' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0x28349d' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0xdac494' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0xa4f41e' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0x788ba9d3' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0xa71c2a27' - tags: - - atomic - - uint - - wrong_length -- type: uint16 - valid: false - ssz: '0x14a0441a' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x9a' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x87' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x72' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xa56d' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x6946' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xe5c1' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x4f2987c0' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xa7a896de' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xa96308d8' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0x4aa125437641' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xf79f17e3e14b' - tags: - - atomic - - uint - - wrong_length -- type: uint24 - valid: false - ssz: '0xc62b79ead5a7' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x7216' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x0a8c' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0xcd49' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x7075d4' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x594a19' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x7b3102' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x7a3a201562' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x7e4e6facd0' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0xd129bd2da1' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0xc63ea61a26189698' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0x125637bfb49157e8' - tags: - - atomic - - uint - - wrong_length -- type: uint32 - valid: false - ssz: '0xda617c2f3ed451fe' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0xe85b' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x0030' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x08f6' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x4e69a81a' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x2b824185' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0xa9d93cc8' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x029199d4a2fd' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x9d1b08fc413e' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x106b80743d72' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x6197dd96ecf4d66d6802' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x6ebb559d6f11ded1ad6d' - tags: - - atomic - - uint - - wrong_length -- type: uint40 - valid: false - ssz: '0x42962c421ea919422238' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x38183c' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x4bc19c' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x0fe134' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x6106775404' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xe087945cc9' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xa135553d4a' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xf24f0511986f3c' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x8584e6f8718adf' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xe99ae370d636d6' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xc8663eba7c0a230ad0b66668' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0xa8df3717fbdd9c8bc78ec44f' - tags: - - atomic - - uint - - wrong_length -- type: uint48 - valid: false - ssz: '0x4008235815a2baefdf67cd1f' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xb6c4ea' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xce8138' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x589257' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xcf8347299fde' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x9bde01fe6891' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x67069d31d0b9' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xc3bbc36ba0041e34' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xd538d4ac70aeabb2' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0xbd4ba0ad2b82af8c' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x904dd3ca71357589e54291468d18' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x047ab9aa3be71e8c4ef96e74aa2e' - tags: - - atomic - - uint - - wrong_length -- type: uint56 - valid: false - ssz: '0x3686fbef9cd7ba5e2e3c40ce8b2b' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x9455f2d4' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x7dbf8c8a' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0xa859846f' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x3295c5ccadee30' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x237c54ea60b888' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x124503bce3929f' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0xa85b0797530de1e33d' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0xdff22a12eedf738d41' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0xf4e42cb4d49efef2e6' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0xa09e2a3a36267ed9e122ee0b5b48d2a9' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x55ab507cf6c85631bb51e9314daa133a' - tags: - - atomic - - uint - - wrong_length -- type: uint64 - valid: false - ssz: '0x999f8c596ac9f10a89cc3998bdc39397' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x28e57394' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0xf20a7a09' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x380babd8' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x49981434329def9d' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x47db82b984d6d79f' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0xf7df795be8924431' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x5d4280908d36a2390264' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x21a21788f8da3d578363' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x76a05c131a00643019fd' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x2e9c64b6da517b55e8c4671bdafc4cd02758' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0x56a152d2b8d8d59469cfd0d572eb2b05f312' - tags: - - atomic - - uint - - wrong_length -- type: uint72 - valid: false - ssz: '0xa6aca6f790241f22975e8b7c2c3061119bdf' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x832b100942' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x772bd943b3' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x276975f22e' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x72ed50eabf7f47399c' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0xf81ece6fdde840c514' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x017ebb0f432d367054' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0xc6be6924d1654977f0d299' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0xb4508d98cbbf7a7c65d346' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0xcf90695615a2ae119460f9' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x4517546bbdebd874415cf6490a14ce431f67c36c' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0xf401ce3f85ed19a1f71bf84645b4e9a71f2a6500' - tags: - - atomic - - uint - - wrong_length -- type: uint80 - valid: false - ssz: '0x2ad38b6a3bac78abf4c86276c824f8f808e06400' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x64749e552e' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0xf8c9c8580e' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x1f2732fd30' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x2468c8a48c1cf3a732ae' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x840a8a1e11ceb202f1b3' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x5f7d5e548ce0eb466e8a' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x5f3f71472a8ae6f0b0044964' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0xb37e1609835f12e085b736c0' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x8aa5cdaec0b4a2629bfa6418' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x168eb650f29bc47d0c4c8b58cf9b8709b137bbafa772' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0x79810955a16a87b07dc8b0c1a4a9dfcf9577368e2bae' - tags: - - atomic - - uint - - wrong_length -- type: uint88 - valid: false - ssz: '0xeb4bf92a836c533c89a608ae004eb8f6347cc676871a' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x02b089a30f00' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0xc67bebf79540' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0xc50d6f74d821' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x2f9f24ac43db3a396c3459' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x6266bc287f8c64628c286c' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0xf57924b1009c586b09efb0' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x73cd47bb52fd266affb9f1d582' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x5901fa87142410b0f7dff93f67' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x19bdc785b0ad47a84c3eb62e8a' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0xb3cc35a048c79081b7531c3863f22fa07182e256db68e85f' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0xf842f2f6b8106b5421a0c1fecbce12a24951865356ec33b3' - tags: - - atomic - - uint - - wrong_length -- type: uint96 - valid: false - ssz: '0x72cea446e337cbc095aae2a3c5e93640fef7e25a6d5839b2' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x415de27172d0' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0xf05c16889530' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x0afb8dda1480' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0xf415f2f6acf3d88d13242c74' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x606e8ca159cf747c2d0bbb06' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x5c9dcdf31e4aba3f9c4ac4d7' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0xf9f0a5567fb0a257d0c3aaa7d049' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0xe2289bc4640ce0719c050495001f' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x7ba9b9b32b8f0b451e23aa27894a' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0xb07d03dfaedbcbc4ec3b02e2853ab725fbabcac133005bd2cfb0' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x111d51b55bea94f7a09833ba58fc12eadd89bd6303be7e3b69c4' - tags: - - atomic - - uint - - wrong_length -- type: uint104 - valid: false - ssz: '0x9d570fd6beea5bd0976389b0a0c0d639c169126afbac747ffbf4' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x7f38444c8aa241' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x15c054c0ed1483' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0xefbc9cc7dd21d6' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0xf09b7f09d596e5f7c5a9b341b0' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x9deb49689d2bea47803b54b8f4' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x145ed6668904b300a3a832622e' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0xc315c6937d4032b16b60d352df098c' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x802b01e7978dbb14d6101564004a2c' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x67cad0a137337ba12a5b5b78f82fdd' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x76ab8ac3e33700d129b0961d18be5d327eb711a97872a22d291c32a4' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0xffc7cefeafb71743e52fae45d3af10e3d058b6eeee7ab50670267e2d' - tags: - - atomic - - uint - - wrong_length -- type: uint112 - valid: false - ssz: '0x5bd5e17b9a3702fc1d084f1af54463de4b1468540b6a224e0265cdf4' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x04eccc8a0be059' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0xf8652563ed0fa6' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0xc53ccb5dc5d89f' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x5ad3883dd42cb304f697c7e2fdb6' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0xf47d0db9757e9d81dcdf8e90400c' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x7b45fe68fdff1cf116093374277b' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x4dd99b486d84eb968f4b8273d5697d14' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x458cb87187700926fc896f0fb6c1d6e1' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0xbfdb858f94ad940101bb3fc0b5fff5bb' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x4f5009ca7d3647669a8cee84739a1f4975b4ab66f73bfe8167c9d116de1f' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0xc224ed6aa70b48e2ebd712424c71fb2517230e01a621b9176ef024669e9d' - tags: - - atomic - - uint - - wrong_length -- type: uint120 - valid: false - ssz: '0x0f71f85b79b01b1fe7a2c01716085e247bf97a1e70e205401656e779f230' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0xa3dce37a7e2288c0' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0xf7c85c939586026c' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x7376ef032dcba522' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0xfe05bbe6fd198c8b675881812d36d0' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0xc120b28787dbe4e5d1d1d581344cd6' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x09a25dcc9912a5060f067ebb672669' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x156e5fb18ed634fc4dd903b75af4aa0300' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x886b5ac9f2fb6772bcf7b9dc97df8091fa' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x30180289c7c9621dc00ba6fe7eb9a91f11' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x71e1d1fe8d902c09822e3679a57554fbd33cb4182f4e3f37c4f8c559a3fd0c62' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x9ea87a56c5978935c7b02987bf6adcb12f01f40d7c25953981dd1a8136c06bbf' - tags: - - atomic - - uint - - wrong_length -- type: uint128 - valid: false - ssz: '0x6b4dea23c03e5c39e56b59a0500299dfd4176225fd5b75ebec06c939866dc560' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0x2d333dce6a9f073b' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xb9700fc713463546' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0x26e4bc6e548929d5' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xa494a03a7a61cfd148277a7295de93d1' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0x191fc9c88f0dce3403390a921609c449' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xf9302e19d1697e780025306f6be1bead' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xb205dec7c2f7d5a74d036f6bcdcb42fa8816' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xd5a66008d4a55b3b7ba2caa3a25d637fc037' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xc57e99045d9ab9a5acd1e25db22b7ebbb966' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0x13a730bf800c2b8d45e18d962527473d217d1c42ac31264759b34485f28e7d01966d' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0xb264c3fca782064a87759b99477ea64d2c36ffac2b779652148d070d289d84a2dad6' - tags: - - atomic - - uint - - wrong_length -- type: uint136 - valid: false - ssz: '0x453ad4e6b79af334e3da39df359ce48755c843d06146522f7563bb9897ebfb15af8e' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x96dcff0a90da096328' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x7b92730bd42b722a86' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x32c3c13ee42c078953' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0xb7fe786c95b4624d4bfe6cfc5e4ea78c07' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x4f8527e07bd97ae51dbc36da8e21ffb360' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x2c5e230fde3faea53a50a9993945afd35f' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x4a15ad9c667f92e002813e066a5ed00c42e7cf' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0xe2eba3e0f72d8a21db64282ab32bc4c9d560af' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0xfc15a1449c9604421c558ca5ce80ce7564a9f6' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0xa55a0f8a4b8b72cf3ed7ebe1d0d32d046c9e0275435cc15766d9145b0810448d8e89d165' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x272a0b996f09a620a57524e4f7f5e0ed793718131cd9d1f5690ca502df6afd2e358ed041' - tags: - - atomic - - uint - - wrong_length -- type: uint144 - valid: false - ssz: '0x91610f5cdd70bf1c49cbe9c933c4991e8b7548c258a4701fbbcdd30e7925be53fa3232f6' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xb9f00a525be069ff43' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xda981fee5460f82443' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xc53772d1fc999a3e24' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xe0d9c26147b326098574a12b4a70d01b9003' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0x25d922c216223a6220d413cea2c702fb9abf' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xf11c800197907f5a9870306177e5d43b0342' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0x57315ec664e1f46477219b441cd98c958af1cb82' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xacc12631f22241abbb23d38dcc5c9d9b1d9c4df3' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0x62de156a948d24e7528d2aa41d545adaafab0527' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0x4bbbb4da0cb920b3af4aeb37e543e4c1f69ef86cd8a10cf9d14b96a06d386441d314fbad89a9' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0xf736010fbe8ed776c67022328b08ca95bfcf5eb8c03fd9aa84ab305be37a6132e554015eb61c' - tags: - - atomic - - uint - - wrong_length -- type: uint152 - valid: false - ssz: '0x9c78522aa7f529a60f14a53a34d4f5c2b28d127b8a6400fd020e02265ab9ebfd30ce51ec5fbc' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xee5321ec0eeec4281aec' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0x2a394ee150113f16ddbf' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xaf3ebed4fe341e623f5a' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xea05fcd5450847ce383f757e0c3a2a14a761ba' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0x3aa141a27219fa3343a7f44e5bf9b14516578e' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xb1ad7d88d393a208f3964d846308fa9df30433' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xbd7e7ac763c5315a8233905644e9d3c4d476292fdb' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xa39dffd4d2b1cef1cb7f103b90a41ba09ba7fa2740' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0x1135c97f0197769f33c5d68d200773930b24884e73' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0x687992202a71ed220bfb42b5d9c3aaed450364de6f258e3b9aefc563c27f34d01b20a3ab9d54410e' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0x7b2e96127558dfd5aa3cf226c1f1183756f2d2866fd49f572b32e908945340c54d7739c64c6353f9' - tags: - - atomic - - uint - - wrong_length -- type: uint160 - valid: false - ssz: '0xbf3508c50dd08982a72d6ab422b1107fcf2e21279c12c60ecad232b16dfd591223604689e0755ec9' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0xf43d8a89d423c2be3032' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x4a9570e26268ff606764' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x88dd817982f546f97e0e' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0xa926f6cf5def1011e1717277cf027bf16ec4b4fa' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x2a12fe7e3c66ef41983a1fa9148f4622a0c2ee93' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x2534f2b76d0a32c161aadbe9ae88cbf728dd8262' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x61414ebbf9b7e8819918e2a7b47cb708446f24b3da57' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x6229c7a684b15dc5004c3016f00a7473ecafb5deb0a7' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x75228f9e430168ae91eb46523f2c4ec5d0c815ea99c2' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x375b68b5ce4192bfd6db85ad08d11193e8d478433b7dcb4284f361889e6a73b978179a9ffb97cbd6b53f' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x0041b0302f6f89ddfa13d107be2fea9162aaedcbfd0782bb3ff4a69466712061ac840470f2d3dfac44fd' - tags: - - atomic - - uint - - wrong_length -- type: uint168 - valid: false - ssz: '0x47268164b3a6902bd22cd077815345785f307791831333d191a63521cb26540af7705edbd892c7dff92a' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x4691223be6e191eba67881' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x57f304df3455740afef2bd' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0xb3eba38e7115a92f53e2a1' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x45dfe82940f14b23db8eee19a8d415908c04468149' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x92e5e1fe9906fc3e43583b197fd21365c264276d93' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x6acf482a3ddd799f0532ebfdb4d21d16613d174cb8' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0xad630e6b8a4a344cb53c0f05288c8bdff4a049bf346c6a' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x5f4095484b931e616d58c3869870114e4465c10dea2fda' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x3816bdd47b3e31ee424cdce98b1fa9cfab60b5b1d2f26a' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0xe9bccccb604aca7079649d071edbef34af17936b60732d8c08271e469fcb33dd76ef17589a5f82780fbfe70f' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x3a1ea830bfffc7c7828bc36504fd45c988998e44c5231ebff1957035e6564a53b2ac0cfdf561265b70d64cfc' - tags: - - atomic - - uint - - wrong_length -- type: uint176 - valid: false - ssz: '0x0fcc536e25ca1d0c56f79c95f63c080c64b11c5ce625a4a3b7af8bbce168df10abbbd5306442f6e69ab55912' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x7692ac29e945db2e622258' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x2489c86a2aa73f04534e07' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x414e5f955f6e145ba7a7d3' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x5aa2954ac8e93c5a8450bce19c7a16e5c7049d602e7d' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0xb3775d862eac572a3126236ecc7fb83629a9a8d9c675' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0xee1623270fe1b03d913a264a607214f93c6666e87d4a' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x6f7e63586a287850ef3b9debb64b5d558084979b744b5c09' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x1de757fc403fa9bddf612a896251fc24eeee9710cab60e8e' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x71672a794fc4e63e27c29b85fddefb5875f31c31a2563edc' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0x24f44fcb5a1a775c28d15a55a98cb5dd779358d82f7d5a67a1950ad26a93a6f05f7f0a29db1d8ca7120af4c9cd70' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0xd1bd48d49abbbb24bf5225b975c217366f4ac0536d38fb7a60c85d03c11c0c31f059ed0a5f84f2896cb4d5242d2a' - tags: - - atomic - - uint - - wrong_length -- type: uint184 - valid: false - ssz: '0xdabe741d22e2c6f09b985a41114c519716a7c9d8531253dd22a9f2ae524902f95c7800a264ff9162206a876a4001' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0x8530f5dda7640a858d3799cb' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0x03c829567e754fa1c376cedb' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xa3b47e9195be530e20c9e771' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0x78ad3d4cbb59b977cf7d7bff15db1dae1fbe3388010495' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xe5e96a1cbfc8c3333bd82f754ac36f0988264690895312' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0x27c27d236bc4e30a0fc2866d20358233ecdda76ac3a811' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xdc02d9051b0475926c089e3872d97d9bbcfdcab8060e248990' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xde52e4d1cc99870b87bb5ca9abecb5e4dd5dfab1975f61f758' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xd60802f2517c7ae6f1cb43d02109b882a952d9a87f2be10f31' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xbc16a2ce35552ed6da38d9c25eca27d9a6d64ba273c4ce663060a201fac1d6c8f9de41e7a68853765a26c35cf258689c' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0xc74e53185367392396b0ef5829e168d8cec041c2355f74fadfc70f8050d1f65a3a81e0d99b4796cdc50f911281771eef' - tags: - - atomic - - uint - - wrong_length -- type: uint192 - valid: false - ssz: '0x2eba16517078dca384127c9e217da35fcea1258499a42da60f95efef31e6f2180847d25a39017acad303b1c248f41f6d' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xc28c5cdaf510edfc2e0cb352' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xaaa9edbc41ccd44b1cd0a31d' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xf4e748344ecf3bb37106be0c' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0x35bbb417d88bbadd323051b1b1d63adc3b259a57c74dd375' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0x93593e9b10cfdb387551b22a4878fcaae391e793e70a072c' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xf88893de2fba7b72cd92ddb1ac1ee4e35da47f86a7cbb581' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0x86f1f5add63608099f756f4a5b30f8afd2bcb5bef2eb9bbc11d4' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0x0c14a66f43d3c94eca9b4e46604c63cc07368cf2d1937a514915' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xbfbf9e822106a039111d6c4172cd2a8a4ad0136c56f40048afab' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xdfa9e9a6aa066179c45742ca1218cf81ec7919d2d2e31dc66cd0d60afb7042282523b62315285e9f49f27b6974a5b92681fe' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0x393e3fc87e9e5e8ef2db6bfde1c3014aba8f337109805d9c5864b790132ae91d072c0670430db657023cbe3c42ab77150e98' - tags: - - atomic - - uint - - wrong_length -- type: uint200 - valid: false - ssz: '0xfbf21d14d9b8d1592a676ffc593933e0490b4e65819f71f2a5904f24c705fb771e14ca2ffcacecbfa269150a6ba9a074eead' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0xa9504d4dab6ec1b3dabbbdab00' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x0514c1c4537b7897683c05f2ed' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x87ca86d1dfdab32f1787872fd8' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0xe9b296dc7f22f12a9ffe5455a196ab9f6174cd4d7738022329' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x285bfc861740d4422a9b84f7672b3ac131894b67d17d6b36ec' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x696b24cad62dbb21c80c5341290bc1fed5a34c662fc7f1a8c0' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x3d9ab909503f0987a43f7a33eff0fb77027d92af73aacc3f6656d0' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x21d1e80e47035e3be9a2e3830b73d3aa9480ef7cdfde86c3a96234' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x76ee4d15737bd76dd42105d4cff354dc495f5a2a371989611d9517' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x8b09955d9fde86039376ec54ec13c3f9388fa911f09a0e5e3869eb62419ed01b598cfd16fad8990d837eba5bc659e1aebab9b8ba' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0xa54d2000c90ce177dfc495ca7ca5ef0aed9b3106e1c9a3880acc3dc8b601e2a929038a28f80d7077b9e11b061986c1d3cf6b9c09' - tags: - - atomic - - uint - - wrong_length -- type: uint208 - valid: false - ssz: '0x7050edb5f669ccac306a1f1de67533ab5548fa81b8063a78eedeefe217c43ee522a7d1455b57b0de6930d19ad76b0e7a300db5ec' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x60a70587424b921f688e1a9084' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x272ac0d2ffbc8e34539d0450cb' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x79d955d54d3ce2b49b57071fce' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0xd0a784e1b73aafc56764bc02beb0657eb04cc22dcdf860cbfed1' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x8d145ad338d4715acabbfe0e54f9b425a571139514dc86b821a7' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x2e13c62fcee76cb80dc9e4c46412781c9592c2ecaad3c33ad2e8' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x95f06b038ccf6bdb21a0cff405c8e77705557b6bfa96f17c306275be' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x6eeaba9f402e9a8693cc38f7eed8bb24cd853e85168c332373e643c4' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x67bfef85b144f955934d0b8ec14213c6c80963abb3c7c4a48b72fba5' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x99a15d07028256113cc25a55f93a93618946b76a42761e70c21d86e4f6a1bef5f3369d3280173b1f1821eda7f5aff194e2a708d5ca18' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0x45f568948261f7b7b2fad45e32d0f0206683d16b3cdf73eb7382099bd0c5b09f017785cc6e23b70045e0a601291d8bc4e0c2e04f3b07' - tags: - - atomic - - uint - - wrong_length -- type: uint216 - valid: false - ssz: '0xd5ac6b88b8a4e25c19e99872a56bf5a4f715affbb4809ae3a5352f4581f18b2d265c65a95b6e83c3622f84ef11a55848e9677ed30b5d' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x518039088ec10d04115f72641f83' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0xf8d30938b67f50782720e5bd16bf' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x51d84f6760f69eff08fec696d664' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x9428c69a091a3408314b0b975a187249e91dbb9ced7eb5c5a7f425' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x7a26e915618532c9b3cf95bf35102d71fe03d669758db716a73d0e' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0xb7556da79f107e7eff39ee8ea7817d11eaa9d6ed54f8357aabaabe' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0xd7ad229946bb78fd478f2a4aa62f8d1507ed261db312d3880ff1752a07' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x62acbf524ac312e53ceaa61e579056607dcf4b65afee1756bed2383fd6' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0xbcefa732b710e9bd9745923cd3352e5937655c7fd0999c01e91f65e9ec' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x0f2d46bcd48f511ca0a49b4f9554b05074fa0fe65581ce0fd12556c82f3a65d4864a8eff5acc6796cc650d20eeba6bcbde102fbf676dbeef' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0x72fc2562bfbbc5e07b4c32c5db9fb5e2758ababb6928b641258367351bd7b3d758548a0b7cf305cf2c7870c6ed7e56b64e48aa57c4b0b2a0' - tags: - - atomic - - uint - - wrong_length -- type: uint224 - valid: false - ssz: '0xca50e1c741eaac5f1813e585783f05f3fd747a42619119c619e9d2782cb1a37f62ea2a351c55a3f7dcec4823998de14d45ad92c6f4a2e5e6' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x58e4d537d0470b6468487eebbe5e' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x74d1c4a560d03062bc81c4016818' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0xf3ac9db14ddd8bd2545dd11cee75' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x9e99426938cc6624d98f7098c35e08f0d82de65248dfd0030492aba1' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0xa12f7d84b2825156744a94ffd2e44e1abd18ab33680e4f991d7e023f' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x1f5005f85947979860b130b114ac2c0aa89783f55a5c87e53626ecb4' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x94469aad2b9ab7acc41a5553c016911cd6aa6bdd856a54ec7ca1d5180074' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0xd2f17ead7ca8859bc09f4f3bd908c89d31227a53a8bd00dfe83952e91474' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x7b53f9bd298e5df2353be348bfa0c43d40b4f27cd0e317115bd655d254cf' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x208d744a6be95dfe72146a118b1419ba63e46b39b49067795631d3b5eb9e954b1e0420d8bee81cd795cb5760e611354290fdb2e49b2470c0c3a9' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x8ac946d0eac9937d9f64125409b7c24d6ecc60073631643d1ed38647474276b6f0e5b4e7be479178be06f16e58ce3213263492aeb229d03055fd' - tags: - - atomic - - uint - - wrong_length -- type: uint232 - valid: false - ssz: '0x896abf3edf1139e4fd56d72f89960854aaab8bfa65e564ff24258f7df6b17f2fa6f646ab61fd47ad6d386dc1e94af185050e69487ca67661e394' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0xf2d67a9c79c02a5123c6af29040f47' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0xc293d764e5372e533bb77c9cb46313' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0xc75690e953d5862b96414256c516d7' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x9e30cea10d935d1107b295fdf60b28951a8ffae1577e06ff18afe34f3c' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x345bd4461ad1d17e55ba5d2a1f424995755f80600201db36ad68691e0b' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x903fa6b62f66a67d818ca0ee0595bcb37c18d41b4096f5059d273b78fc' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x1918c061a0d6f9c03fe548350f8b0dfb31b732401d69125a23f0cee95ea668' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x6be1e26807020d7ac20a40105e94ba771df7acec79a9a18ab8493208e018a8' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x3d69415d303bb691468d8110b0c2eda04e5948d8647d2d46f28a2e5d0c4d9f' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0xfe7b5ebf1a78dffc0f0437721a09b86e1bf1187d8344aa9b71e1030483e5aac0d4a780103509aef7e15e7c31204382da0739fe8f9d703c5743015137' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x2e97efcf05447569f7dbda80780cccc149ac3b7e276abbdf455b3b29f61ba925f92fcf377133b490d79b874115d1a639a7a9cd662959b45312a120d5' - tags: - - atomic - - uint - - wrong_length -- type: uint240 - valid: false - ssz: '0x04ca4031fa6fbb9204f3c2100dc119788c82ed923a6bd13de8ac55e48c21a2f07d298f622ef40e149b6038c095fb3c905aa01f3009fc6da9d17b0b7c' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x78f9f6a85ea67af61cab1b0ea908fd' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0xd99708242bda088b0c077015a80c86' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0xfcd1840ef88fdefdfdcfd16f9ff2b6' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0xb659b2731c3c0db04db896c6ebe5f80d3ed70cbd9caad51c199a4c8efaac' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x68741606b549e7d56f4fccd90274d608737ca9fa3e5087f7fba694dcb140' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0xeca7a939ff404a979bcc576668d6a84d13060e03c4df7ae42f0ed754e0bd' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x93eb82d8052da2f04ed0f93e3e6b3d08394e35137b3b392c472c619ffd59885f' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x6508a966ecb521f3e9ba1163246cf4503ae50c0639692fca0f48be957d133da5' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x756985c8b372723c4f96e7b7bde776baacc0074dc1edb9f0912e36b75b1cb7d6' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0xb3457d0af543dd7a8b4e18f2f319cd4ada3c1b05276743a98ee74a95a9ad6c8cb22e12cbf3eb6526f43e86ee7ed9bace8d153ea840591d277875f0f933b5' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x32a966e62e2e3df54af0972de7438543612515139e8ef678e867bac26dda462576d99b69954b508cb73649bcd73969b9c15f5fcc834c16b80c85f1a4576c' - tags: - - atomic - - uint - - wrong_length -- type: uint248 - valid: false - ssz: '0x221f600cffb6c9f7212d35783179d06d61ec6104755c06c3531bb5dc23b9d907d1d0b3a5abd9beb7dcae3f3ed72a793f9c27818d61e8468f05f49c30359a' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x2f62847ca5956834e6f0b942d437c6d2' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x351f7be0a692cff70f081079bda87c4e' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xeff1018d1b0c984628dcd5a8cf677d87' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x2a8fdd52435a558088a6cd9c5d36aeef6143ecf07f92211fa2a3760e5df3a7' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xe77db02c943695344e04fb51f9e67e567a59ce0a457eebc4bcfd20aa346bee' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x3b09e8004bfc682443db0958d0b6bfaf1d7f8a4c9e519797e10c0dafd11e62' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xad70a58a242f4aa655b1440988aba54528a0349e142cf90fb8338fccba50344c96' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x8909b9a8fbac5973ea61bc0d243a20c276fc2ecefb7500ca58bdab619b132ba3f6' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0x15558323c4f34c89c54a185c8d41cc067be32a1f6a57bc54610cf2ecbfb0f021de' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xfce4efce47c8dc11c78a1297681d9e9abfad627e4b88d72022ce5ee38712a305ef1f05b1bd1b804384338b87a5c2e149a875499b1b648ad08610a872eb2ee73f' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xaa6b4a22ae178f10220366673540291ef20536d5ede22acc77e216efa79be11bbaf3f5746c2a988a14af2cabfb51537517cb5c86b5607029656949424f426bc7' - tags: - - atomic - - uint - - wrong_length -- type: uint256 - valid: false - ssz: '0xdb987d1ef845b233d63426a67f763113139dd2b0300b0b3e1a84b0bd8134257399871ac844349d1a3d76441de222ad3db2a31cd5278cc684df33beb2a7b9c56e' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x48dce9f8effcaa1f5e41481ee0b9d66e' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x7a9ca3984bfa90a45833853b1144834b' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x1e0e5d113615e1bf15048e88c61853c3' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x8d288625ef557bf685f8ed3bcf5da6c766b7be14f062891f321e862a93d5ca37' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x030bf80fca506c162bf077cabb8e9511ef5bbe2f6250b83dfffa3021b2863f50' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x57987915ce3ebf4958b0b5d7be0155ee60149d5b574805726a2329ebf3362ac1' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0xda5e4a63c46b04e8e8c1b5c42d601fa02b33a5b7825921ba13da79da5ab1825b527f' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x0c707565e044b3cad0093824838e0c4cef96e4043046236a28131d37147516e824e3' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x82368e5045bec61002b96df9ed8f64354d2c9f99dceefa6399c4b83d77eadad5958b' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x8e76029c62a0adfe80617259d69f162e0971b8d76525c25b40678ed6f8df672919a2a607f3c8917df25071ba5c2da7aec4d5ebb90d2d23e58c65f5f89769de256fea' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0x12723eb9a78dcfa566ee4e2e666bec777f53dc29735ee92f79ac8d0f44095d251d78b6e9d0fa8f5f9cf0e0fc629f526b5b8e3fdfb4f1df35d08f5ac91f0886aa5a9e' - tags: - - atomic - - uint - - wrong_length -- type: uint264 - valid: false - ssz: '0xe8b0aad4cd2a5b4f7f399f7f21f2fd05965309fd364ccd9874f5bdcd9e141505b93d5f8a028610d7d40120d98c657d9d3925bcce1ab17692c303eda241310dc04094' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x01bc9be95e3e8c49f6980c3979dcd11bc5' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0xb220b46cb44fcef46c0bef85f27d9a9058' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x1b515652ac759f17e648af184cd867e8d2' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x61bca095c978d8a21d475930cff37906d425f89c5c28eeb0d2b6af340ee5e4162e' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x054523c188904a8ffffbe2c0b7aeb550c926f0a2f521237923b68f5764d127c207' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x63a6541f2fca16b828512a92e0063655006c9931a756b37b15cdc1323ac0371fea' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x29b675df8a170945c26ee24ca5939b1708277533db1fab37ad8eaaef0b82aaa7ae2c43' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x4d8fa043d7a134ebc04ebd64fcc86a56a8fc9e2d5f7aa3720679383305a7f0094855fe' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x3fab258e761d125a2068fb51513340370c90986f663f40a22e3cd1225154257e4c5d96' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0xb2650fa3df8e97feebe7c6222a473a781b392ed6bc35b4f4c3f26a12c9e76c9afcedbc11c771098f56c1d8b69235978e71d2bbb4edf07eff58d99526eaa94d388d4e8e53' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0xae7ee6e6823596ab0f040ff2ac1bcd07171b252f92af19a21ba07ac74fb81b8921b5e224e978ae7dd7cc8e3fa7e9bee6790fdf86e9b9cd827bf50489a0735da24ed6a060' - tags: - - atomic - - uint - - wrong_length -- type: uint272 - valid: false - ssz: '0x21e2fed3f4198b6a03129c519a414ef6b46e0c43f500007812dd21a8c721a14e4410d0db6f0b4ce77a8c0caab69a7da9ff5a2e159e6feae1420c9c5a3bd5e6de233f9c45' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x20679650168042e7677d24dc00aa018aa3' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x61fe9acec1e52e198504e67be87abc9dfe' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x71291d17ae6b1a64d7fe1829079b4943ba' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x2937a8b026276b7dde49129005e22cd808d05d74a715be34346dadfba8014a6c98ba' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x8438bd05e88727913fb8e90627da5607aaeaf4805c1244be23b3639f5f37a7534cfc' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x4d87eb91e8d75ad6ca672d2f5a0ec78278a4f35607a5ab6d09d20d086b6e1fc1f291' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x1a39fe14563feb9f14c2b3b2c28dc2ee7ef07d92d2c3573e2c071b6a9b3b7959c922966c' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x3e37d30e5cf68fa9aac9a44baf5d1ab6f391324fca72a0420151af1989c4cc9bf352e9a6' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0xf2716f5a3802b875885f8d12c5554fd1baf224dc635f93c7f3e759acc3edbc02e3adb28e' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x2c2d47b4348dae44c85f14e88e7bc360539a51ea7f2fb66261f7c0180f2079135ce8ca04295f704d88a24320573304748e7c89d4568f9386816c11fc320eb03ee513bf769c52' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0xff480661766dd744b10c326215a1c39703dded203c3a0916e57d8cf97b225e3addf0c6f03ad494851c607491a3e28ae53ed495288b1a7bbe07c0e36bb985820b24ba1cfcc00a' - tags: - - atomic - - uint - - wrong_length -- type: uint280 - valid: false - ssz: '0x2133ad0019ceb58f7305f1ac03be1f22d5325e50e3e06226f4b085d8f7a7f4a7ff10b8bce03e4dcb3774cc85eda0346cfa37846a94553b1e14ab267b3eacc379cd1b0002b301' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0xc310dd567d0e69393c17a3ae9c2dc75a0b7c' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0xd0aca1916a6dc03f98f121f5a57cbc700d7b' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x2f0d5aa54a5aff51bf7fb54f2cbaa946816b' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0xacc6622dd7b5045fd45f1f6b117de3581fb5bf16438805f5a47bb50ef401b69069520a' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x5e9b87515ed5ed2ccc58ade677a2c57c1ec592beed3a9a97edaa9f86b06da10cfaefb3' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x6a50a6feffa9610b1872eec6cd3a345ea88131542505c1d9663d17bb032107693a37e8' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0xd46a68e1a3195a8d141109efaefe94198ae4b96ee8fa122a5d0029276d5aa50934792ba8cc' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x42b4dee091b9060c1117257a35575140f3c7c64a69982b2b3e5d32d88fb01dee77e3af4f71' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x0504d2ff51eda46950242ae5aabbc67a7fb2df1dc2022e52d1d95be76c50314edf8e3f37fc' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0xf5340edb4c5d7dc8e47240cb95a541eb785f64205519c7f99c71408fcc2d86c0f4362b0e28b4ad1bde6067030f7c18d9c373670d443dbe7ccf96220b0e3a0bcf0495927d4ba26a0b' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x477273a89b963dc60334b169c25060898c558f8e74a89e25e40e73ef4f51beed5c14d3fa94588d5ca0b1fc376e9c9e61e51213b288c6cf603f0d513322fafb2d2b8d439b3d1e8824' - tags: - - atomic - - uint - - wrong_length -- type: uint288 - valid: false - ssz: '0x5078f77e45b10fa9e677f878ff576a05060c7e1e7fe990e86168bc9ec4e5060476cc01571a559e4526d6d8c25025fc724e18bef22fc01bc814eb24da150a8338c5ddc9d7123555df' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x2c23ea17cabf18c980634b778b1701051ba3' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x0b0fddc6e0dfc9a68c50958d6c9667ff8838' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x3b76721135a01cc8969ce590790e625700d9' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x57f8a4c2c20a178ed7036d4d14b6968a766758ce9cb3104906eb564340cbd4d75942a4d7' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x216a513d1c54d7d6a2cff8f6723504a6e353cac562eea9c36d1bc4c5d9a737c20401c94a' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x2e26dd126e4164b4e8e8c7f8ab8aab1d7f2d58c2c4f05d11355288bc0f446e911e87b4b1' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x915232e4386d5e8d30f0bcc31580473635b093f3c482c773c1670c7a3136bc736766ae488227' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x6e14d0d51210ce5e37cd7ea5cbff91f062db95740c8c1e781102b3020b31e74e8b586ade2093' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x8b8e620324c9caf8441d0c1bd85dcce28e02c65c0645e6948fa23ef5e9f58887b2841eb6b6fc' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x9f8e79f54b24813e5df4106edd8c8caec62c26b2fcf399e88c655d6ca81d6f1e320aee87f6e1dd5e7f7a908c3fe847959bc82c49c9e42dea58fc291ab7a1f9b88441a0f17783567386ea' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0xf4f52aa66b006439088ff0221a4cf25ad0aa39ae8abc0399f7cc80df2b85be1a97286304727575b49cd317cc1ea1d2471845adb40a32313664483f7b4bc0d67846aa9089f9363db4b350' - tags: - - atomic - - uint - - wrong_length -- type: uint296 - valid: false - ssz: '0x51d9556fa9e725afa0ca9d4583c30b2a0cf93fe408f4bd234585cf4193d3215f53a25ba9f5e98f2a2d533c3617ce37353e9e6bbcbaaaa56179988ebd19f45fa9b896a2ce3200ab51cbfa' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x303a839291ad086162517f19a92a84f2ab7e5e' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xa75a547f682a7b4fde451def735fc0406eec6c' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xe9a56b46547c248ba4e5b482311f3e792e218c' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xf1bdad7c28ccbd5872e96a0456670f62985a974be26770bb17b1845bd46eab9029209334a8' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x030fed1af01b928743a56a1cdcd722688398742a4c51ef7119d53d051961b252a86eda7251' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x669ff012f61860ccd72f2e831409db551cf2affda440f1dc072e46ab4d6df724ba02e3c5e3' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xed64c6775a14ae38528c162c520ef66599ccf69f77cc2eaf14d1f00fa73e5b74ffb9d330025e52' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xc86f57ef28f5fa9e7000fc813241465926f4ef939f04c267133245c0797027212baf35f3c48852' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x28eaca8a08016f61ab10a3f06b3b5464f16383382b26185a67c467383f2c9ac9483377b4b2c2c7' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x08215ec41959e1fa32a44c3eba65929839712f9908f8b37a0353d768b25eb0efe01e7db2235d2bd709a678a47c08ed8af696a01017628b8aa0ac226702a8661ab502dea5fa69295f24894668' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0xd6512afe88f040ded1122eed137b49f6e17acf61cb709daa5107c25476892994298b0ef5e881c7db591e75da6a941816aebb438756668b84e9a9d0d28f5bbf1d243ab764ffe9222165af2b45' - tags: - - atomic - - uint - - wrong_length -- type: uint304 - valid: false - ssz: '0x8d28eabc07106efb4d6f35e5eb5d2972e194aded25d7396332370bb2d7541fe40de7b3d1a62acf8e97f1a8fcb161dcb48f29a2684ae62f8a692ca11de29e6571b783ef63f536dca0945a458a' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0x855e288621d2bf7a2f761c2a15b2e8af6337be' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xd80aef54eee6d9b3db4155bad8147c10610640' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0x45693760f76a7a237030573ee51224bc5e8289' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xd837c933b938a5baeddd93588115ec15702f30faaff7f5cb4174eac091be534cc2741b5b8c74' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xd8c34a12aa57d661b1b8815d81371e5b3d5abca6b227e3014cf0ad7bdf50f9d7b7cca85c3d9a' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xb7603e633f6a080b82dc3efa2433d301bfefeb523f9161dae22610dfe49b779122c54e9c0b32' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xff2785850c99508fad5d061852b46409c4a484d481070a9755f89652b29af4062c9a3b8baa67183a' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xeebcca8f46f64a335b5609b27287dbbb57675382773166bbf1336d5582aa80d44db8abbd2ada103a' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xc8f0141ecb8e766cc87405b351bd630669052a21d62fe438aef8d4e9a7e8c85a657d5434330df607' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xd68ce5729bfb6049d2afb417c4748de554da96567d9762e8ec0d2b022e59f8a1066ab63e15eb641a483d532c423b97a13f478b74878b9663084c99385ab693a8ccee623a006d5cab773c46ae6eeb' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xf1f963f1a2312138c34fe23a337fe7c669d51c7e5b4fb1503bbe31a742a3977be390d007fd05b9f247c4c8dd1c3ca4229604ca2817cc5c497ec69398d38bd2f64ab6be8da2ddb67c660c29cb1d98' - tags: - - atomic - - uint - - wrong_length -- type: uint312 - valid: false - ssz: '0xf6e4e5304c84bf6f714ec2129f35d6f8c630e99e1a8a2fd196b33c0ff578a7e0bd4be0d83d57a544a0d91079d21050c7777309f8b4cf66e30cfb96f852b37e44f00354d4a257388a96fc7c4c9f3a' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xf2a248bb3ed1112cabdf5396ac5833b9ddd24f8a' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x0a890ed36f588ca10a0ba7d71f0a70e3431256b8' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x6cf8754e2bb01729e49585d885956355a882f0e7' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x7df3f17866d1927199ad3094e9542ce157f36ae60c5ec758bab761d3747296060b013dc2a1b438' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x811944bc845222c9678199fb0ac2ff5067be385e1316608335b92fa955bb306b19fc2a40247420' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x5778b955b7708665431c762e91835e33c2d4ccb51c45afa387959b7750447eddca3f5121aef215' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xa93294cade3b97136bffe0793940f0667d5eefec0a35d20d091913b1d78d6cb996dc649b0c74545982' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xf66e7c4e2383042e49fb564bcd0d7629b1ce40a3d002168e1c0a005b8c06f90797120c33d5486dae7d' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0x2c8f743224cf91d7beb205cf2f93d54390ce0297f851b3ba565d9441a411f321c0cc28f85a000ad453' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xddacfe2503ea2b6b9d7e1ae15f5ca747a2724f9260257c1ca534a6860eda8f3fece2e4ada941cc3d9443fd28d8b00f059e2b273fe084bc9e7aa5833d3bac83d316928cd24a81ddba0ab7c59f830f78b8' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xab2dcaf86c06d782b8617d2a313a39975fc7006e46f2c51271555b10afbb074c2fa351532220abed0295c65faab8c0cbe5e02597f7da1dd85aff760c3e331b7a15b83475cfe9f35361032d5229693ac3' - tags: - - atomic - - uint - - wrong_length -- type: uint320 - valid: false - ssz: '0xd922c02d80ed66c4f4896014dbec7dcc995c9427abedd217f436fc7e9998b686b67c54d6ecb5ad62ccb0f78c5299f244273ab0ff8f09aee161d89fdd2f6bead012708c9d8f4c36981e2eb55063339c4b' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0xc3d4a0e6969675fd8ac40ca7ea9df1239e38ff1a' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x67365f5f17881a4325ea76b5cdce43f8712bdbf0' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0xcd76bd9457db77cdb28fd1c0eb00617f66b0436e' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0xe09f110e65f74e0074c3ebb1eb0c245d1556164787cf34be2add7755a40915798caace32909b1640' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x947f1927bcbf454ba5f0d09e5bb9466e728f493b7ac192b0d5251b0bf3d08a478bbea4f96a09849a' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x5b5beabb6fd8afcd679b797c8fccd75f3ac3d0b7ba2883814a0551afa05234e34fec82dc97d869b2' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x0d68358758c0cf580df66b6d2ac072e4908c7b45baf1136f8cd2ddc58ec8ecf9fbdee5aacbc0ff772d99' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0xb1697fe3386135b645dd734584891b967e6a1dd9e676a8160f42c941ec5d2501b045a6aa698711a1b89e' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x684868e9b5c2ff838f71b9d7bbae598b1b4c44d8e3ceab88fb64d9615a7dce3a27b5a3fd5da3b8a11563' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x0b7539c3a4fb6053fd1121350f192814cd8acf33aa4f6a1e5687d56e439ba372958c34a2ac117695d7ddbf10f40f2a64d24d7bc69b7df7a5b3849a9a5ecf7f956d44d1b219bbed37424b4b6db710025f001f' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x24ceb28b3e7dc66e6c9075ad3f9d630476207a5648a16a3774d2b74fa36462aace758c157579a0bddd0146caa0311a161fef8bc65457fa6e43dfb099eda4cbeb9135140ca91db5a93299e38974aaa4651e82' - tags: - - atomic - - uint - - wrong_length -- type: uint328 - valid: false - ssz: '0x47fa3723e586b6c0b6899ad9ae29397b66c75b020886d4f075c20586c375d22a1eec6e7529588c253b9521de42d5b7153009497855d5f23080938ace8427db4a09300c7f4dd10fda6658e101fd7583f5392e' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0xe26bdeff208af7cc818e99b4eb7674382be06d618f' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x3959107db5d31496041d2289ef157c285ad68df3b7' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x6a9ace2177fd4f222628b8b5b373fd2a7b42267741' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x93edf98fa992d59f2e60ec6098f1d511e2e0d745a7e4f282612f411bd98e78d56b6874f0c383011660' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x6e3488458a86445ba5a855bcfa8fbd93953fab19548f068eca0b4a183f7a9c3f7c635090cb9cce59b1' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x47b0499bfcfb3d3d62cf584c2a79f0727f8141ac822da9f00e4dd2e0bdca17b7599fdbfe519088b9eb' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x4eac803064c449d1b66567ef9d5c04e09dbe47759b6e3076ad379a56ffcd40263ee27d3055099225362ff8' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x55b89b6649419d786d3f544101939c5e0c4a387976b498aef99921056afbbc44f7dc855e5f184922116da5' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x9e6b5960f8738bcb38bbc9bf490e5765484141a24067911d54aca7ef168bc7d1e6dbc59cd40467d875212b' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0x1d11c17945b4917a9700dec6c58ad1d7eac122e15861f2893ddb043de4e9e7bf4b998ac6f209c4e26d0bda13fbffbf0bfc7833b87b3ed8ba27baaedfceea800838d83300a9b68848a93b54f095aeb0675b992607' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0xfb6c98febb35f15b02c603fc9721168d48d44f03d97c9fa61e6f5a58176d26b4c54ce5930a9cb240bc60c72bdb3bc03c5c444bdd58bedcc5b56af95e7307588f457bacba8296494d22707a3d69268b8813f18dfc' - tags: - - atomic - - uint - - wrong_length -- type: uint336 - valid: false - ssz: '0xdf73d5203c529216b16eb741be239b51f7c9388ac76e6882d15950094b443b280660757ae5a136bb6244e3d06814eaadf918ccd5425d1853e64afede32e1e7f88c9d35f44acb232f91b5b0b2015c228c4242d5f0' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x826f9f64e5994d360bfc783830478f0b57864f1bc9' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x050e08c4f4ab9e90b44f3654e8a13f90d2f3b4b4dd' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0xf3432fc443bb998eb861595efa1b3cc1eb9d356234' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x8245ef41e9fc35aeb40bce525b407ddd868352747711c29b8ca363c22ddd8c7613c5c0de3e6be10feb0f' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x0a25412f8b4a9830cb1a43a3c1cc449a6cdc9240c47a1f8a6f74f3f55272f7816e7475e6ead95791aef2' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x3f354b99d93f85e092aa35ac28bf43b8adc7c5f6152f7cfb3448f30412f42f9274c8eabc246e3b0e9ef0' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0xaf029795bc907fc4f8e2049a8ffcbc50fef789172cdbd65ebfd98e898b061d0b812a555c5fb6a6a5d2aa799c' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x393176039842d6b7371fc8518a1c5dcd9c78a4226e12100a33c9e0fefce815e7efd86dc7c9c28e18822fa609' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x8adc416b89ead9d696fdba6eae2d0cf93c4c1afa988351459d1ea5c18154375d28caa6fe48f47717921d0cb3' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0x397722d9c7c2af700ad3a65769fbb9e0c4737a68ee276e3a6eae32f609b30b4072c6266ec5886bce9988606f6ea9e6d7355e3b360d14b82fde67c82e52c1f15887322a5221271e04edc482d7eb85123eead007a08048' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0xe9bd9b3a8e8ba0fc07f0694ec71dd99a731863b8e64aa081f0dbb988f42b1f0dda31c0b05579564822bb497fb1f1f66f42d3ba683a8fe7ac533096ec517dfcc035e959e70eed2946503c4b36c62aaa3bbeced3da4d65' - tags: - - atomic - - uint - - wrong_length -- type: uint344 - valid: false - ssz: '0xb0e85268f023de0277b3ccce78dd8cf8be5d0da9b69685bf922a6b1be876051330d83d80aaa2a3bc07ba9c755b4203d8de4244f72943290d482b02d0cce9174723736dc5916d4ec5cfc358af6ea29ee7e188ac62ffbc' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x6957ad0f08f832fd79cb30bcd2e520d90fd133bfe449' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x7a2b5cb363134ded17e75bf4369d3c4e51b2f7f2cdfb' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0xec427946ae1850dfbf5bb19a4922aee9f3863fe0b4c6' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x9c08d6d9f468bb330e593d76f0d754041966ee61110d481021167cac49abe019859348657c5e6c1af5b0c6' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x80a12ad57142ec2f25f7b884cdf05ccdee44cbeb74963cb056cbaf7e9e4a1206ae57432db2119605dbb31a' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x01a71d02811c364165f067d6d00fec347dd389ac6067958184e7bb9a59363bdea488daf2d2a20cbafb93bf' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0xc8ade857a02bbb4ea938e7866b95342496c009d9fd5f1c93d972fac414729c196fee1217ee65b48c83393c0fbf' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x25cfee058c6a5618f02072c1bfe4ce37bf2bba701ec2c8cd58b960c7fbd0e27d48dd1acbb65c6fbe329dd22b9e' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x1065d71eecc8b510648f5deffe9b6c9b026a6df7987bf717fd491b6ac53ca0fca89495ed488104538cbee44eaf' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0xc19dc3df8883914c2e1ebea4b596ff6750e9810e5d0eadc41feb9838cc549d27a6f13723ceb45bff12b1b8355e030204ada66f43fce4be0ce093d5ef09fa04e95a22d481c1274f5f6e835a8a2dbb8fa491cc82373b149858' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0x8644b7a958f33d49717a37cdc5b9c946d5d417601abf93a9e9082540d165aedd85a6cc06ca91e163f96b15a80461d2a659211a1cc9a9a9c85486aca5d69539834b6b69a694d8c0fb660f3abec7f3ccd5b71b600295454a12' - tags: - - atomic - - uint - - wrong_length -- type: uint352 - valid: false - ssz: '0xc9fe757c1bb286962807a2187a6c906f320cc834bc754d9603a60f3d351b64769555ff25d471cf8a736d9b74feff9e319e5e895a1aeb8d063bf2f6065dc3ba04ca0f072cbd5452d91c2f0e135e2513e5d78e19421b522ed2' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x8fc58e1c342e4dd5517d9164bcb40dc9e71c6c47e9bb' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x679a96deadffba35256d57a193fee28d02ebf02f54fd' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x46c08fea327b57dae0291c19baa4a61c6eeb7aa88ae1' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0xc612f5a3241a96e102c0f47d1472d6128e6c8cd2fd887848f374388604686d7cf44c4017f68fb26cd766663b' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x38a1bb1eff721f6456c2531c6f842bbd23d9b46b877999ec818d1a5800f02cc1c457740fce32e25eae021ce8' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x94c644aa7b9a32b533acfc4165f2caccc67436b2c90e2673ae6898a436e89839ad053fca12cc86fdc657f002' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x4e45cb5434dd6626abda95a585ec0203b629301140549a6a872e97a17eeb3439783bbc5f8ec50e21294bb71be714' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x0834b79a0ab26c25cddead4034cd790a2984053fb5be498443cca6e3e9dc8414e7b31b96e8da351538f5b3b591c3' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0xc394c679ebf52278f00bdab091a743718ea6520f8106c8dfb51f92b0fe93384cf4176631ea0872b9aafd408dbf56' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x19b1b58e4e4e737f4b0c70947c9ffc2335bad223881d832845d71b63fb368606f399816ed7f1d4536d303c8dacc69ad5e84f1158bafd6706e71ab4a14513f23bdc71f0c653fc8b2f14e4e0d68c964c48c0306e000f42fea79d0f' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0xf25258f9353399dad59d61266b80ff08515426fa8dfc6760930ecd78415a314714b0658930cb0cc5a037a8e0cf24a42fada79ca2e88117be2fd5d1a8ff9d5e7fd96c56e6c4608da5475e431e3423b36adf6cf8d18511aa748571' - tags: - - atomic - - uint - - wrong_length -- type: uint360 - valid: false - ssz: '0x27c5803760b42b535ac435d1e84b01581fdb73f32c8bbb173676356ba08247f516214143c91f53f9e947f09c6de3235974dc1a8f4e6c71837ed02b5044865fbf6092eb9a9ba2c92ba8c4774e3ff8a639505c7e2a70b05d28b281' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0xa9af165e27eb030e82ad285116d1f458751af96abf73d7' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x84077f4c4e29029b608185a9bfc7a08f8adca4c5175124' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x15289e5e78842102ca26614e95a68da6987d1f8419248b' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x3176892a5fa9fbaa8a8ccee430d6ec5b39b70980234ce16e8f7c10e88a6035d7a3e05fcdfa3d8fd85decc9c5a0' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x734189e539f242ff08a012b74a5e460631bd885e9e051751b3e788101932ff8a1ece66bc841fed525277e15ea6' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x21e4ad59caa377ea662815733afde4754699595c7a9b9d11b476450645411e94b7d9b8cbbf71ecba9f4a1bbcfd' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x5c0664fd3152c0e4a7212f2292f05133921d403c01813ba82e4eb660cdd4363b2e1d5e43d994f151d359946ad55f1f' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0xd3a655da15f13e2c60b8c3da0e5653eacd3927948694b25bd89a1294b0b67728badeb6604d2b6e3df6f148f777a149' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0xe09f1ec9e6cb9526615ac9ed4940175715fc3cb82879b8422af9d419b95f41c225d78834b3254ecaff9e599a33c812' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0xf9d570c08b4313c48d4599aad7ebb1e9b75bab48d126608c13558a41d36858d4a6306e883e816e61061366d58e5d874fd9b166b3c588a9c073cb7f42ec9664ad728572afeba9c41786abe723d796f7b2b351e19a3b0eaf89ca7bf170' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x7bc782fcc76c37d97b820f94cfd1a933c2a4abedadee645d04f2cb8e992233698585b61a9b0918becd63f65d52bc26993e52e50cc5eeddbb07bc38c167968ce6e418fa079148ef9c709d5b1c0ed5d359ee4413f700a620ad651db796' - tags: - - atomic - - uint - - wrong_length -- type: uint368 - valid: false - ssz: '0x2f797b04a31090298ca32e1439d3e46e46f76e9668d9ef45f73ccdc7ca33648e3180487b7c819a48ffd50d74e77746619bdeed83e94f92c116ad444023ce0431bfcfe25a685af40fe18779b0320b096b722b160667820b9235db4ce2' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x4a6099af52104ba5cfac66495604c0d66f62536fcb62e9' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0xa5ca188e863f36fdea55166d6c6a8fa79c7015d7f45768' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x0484603bb032c4ea9d70b9a634e5faa124547fefacb45f' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0xa0c0403f73df56a6d917f4ff50ae210d5ae0b0f95b7a616ea68585bf1903e2741f0370763ced027dfaf91e17dd42' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x30f0324746aef564e65e2b408697b124526967798e0dcc07cb7229e9ba2df7cbe38606aa6d79f8b6930a9c97ef47' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x37132e6bfd590cc95e5ecd716f990d889dbb7c2b22d5beee261ce1adc84d5f6bd1f4304d461d54114ba07f9471c0' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x444a4211f589ecb52445f1f03054f862db583d7c2a82e5be13cfdc88fbd31e4da53ead95a2e64873b2be96ef8e0b28f9' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0xbe2ad6689e9c7b5aaf20f6a53f996157e81cb2c3d07f2cb5e9668e88ec1351bc8eb6e291bf5e8c1cdd0e0a1306c6621c' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x418da1c0f2fa7635aa77063f7650f643f2250079decaa1066fb4174b995a0032d6b01f805316aa8772a234af903d60de' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x0e6d83dab2112f39dc1afe5174103c41d541654aa011de9534efa0c9a8d3cbb97d517dff2688d8290ea0d4a70733e77d599f35c1b5f7787884f020413f027d4190018da4d8d7eb567f38bc1e15dffc34e799d492d5f39e160b5cebb678ac' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x84068efed07cce4a43493be1ab57c012d69da4ee911081e2fc02267aca815b2f3451dd254dc8f93e590f3d6451bf42c4929d8f398a3109241944c0f4eaca59cb866c027ae53079e22c76088f980d4d12c398b424044f51ec4eecbd8cc479' - tags: - - atomic - - uint - - wrong_length -- type: uint376 - valid: false - ssz: '0x517fe1ce76280b7bc53f5b48197668318e28ff1824e391e7490d10bd00c658fdb68863bdb44bb8edddb753ce89db7ff4c32131ad20780671afc0e3dcb8f480c8331d8bff5a92684dc15b583ef67fba42a56dec0336c93f831f0c33576a43' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x5f1172192cda7158f250500697d0dfd14f0b001aea853b37' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x2ff04052d92ae854a5ee0f497439965d608f1459865986fb' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x67715c265fe9ab327783df021985ae4d7d9c8d4f61053c0c' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0xc6749e3633b81485aba20b5d22f2503ea488ac67f906e5308ef96734d5945b35b73d395f4eaefef757d3957b0ad992' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x4a6629a018355414447972c3bca81ad3a3be6f9ecc68b65fd442abe80960572eb29a5b6238fb0a359c4ff7e0d20604' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x1f797fa77bd363c9bd1658387baa08f3146c25f8a5e94b4534897674cb419c2ad9cab312466d854d632d241b196b3f' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x616b4b15832d8f61abd155934e26d67a0a8aff5844f739311aaba698314103b6c9f550e37bc059746091b4790225c1b5bd' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0xcb6e4061fe6829831bd249e131dedd53b0b896a2ceea8b662c5a80510bc12d9afa9dc6cc2bbbaace98aa26158f4ae7db17' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x6ce558c9aee49c1dab59843e277603e382646f6e6f63d21284e39b9d7e531a548dc1f094aead8f6a124ea730db55be09e2' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0x5608c43ab055b02496a63e28d035fb5847ba2d51bb722059d2dd9ce2b53190ac745d9f3d8c1c96c06061a8bb3cb36d6d924acabb605e820d7fab4b364c930d8871afb653b038b41cb47bd413326ce4ee96ff2f01602c1be3c6cba441a1441314' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0xe244771c96e8e64f70993aefa16f1f7fb9e91e35375b949078cc8dcd6c9ff673ed23a2286458506405bcc99b5aec3f2b61cfa735568c7768d6cf9bc562ee3ab2fe78ba02e7268a893019ccb098bf302cae136c9386198413012f394e33d11599' - tags: - - atomic - - uint - - wrong_length -- type: uint384 - valid: false - ssz: '0xf71eb886dbb6f956420e4ab15ef09a0693ca30aeea266a1b15460ae357234c0c988e3ebb431473df1791e2ee39f9c22fdcad0e00f5dde397ba8cee53c4703746cf04c3c856382e3975326d98c414aea429a3c6b6664548dfc0a94b4fefb9b489' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x0d64005cd1c82bf7c51a1b06b749b1e34d87f93fba39a356' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x7f43cc159c3dba717beb450f151b6c84756d430b27126bbc' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x0a6de4f64fc7bb9e91b5095f792abfda3491444752640089' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x27175ce9908bcbbe2147651c5461481766b7a160273104423b333ddaf7613d4b91a5744bde16f2793ef78987b3dda249' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xd7541b39ffb5ec9d1d097e5a3cd1dc0e2a0e2c404ea58c9dc89ba5b240a4aa3bac9319f7a18bf84a40085d1db0ae0f67' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xa721afe3b1fcffa095662bf7822d8a260fc3ed62b6cb4c86e920783f08538f41f1a10477d9e6ea266d3348b3bbedfcd7' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xa32be239cf784e1126ad39836e72bfc63423975d7b641e780034925d3f2328607f88f0ca964a15bf8ab7d0d9998bdb26dc7e' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x8d355360078580c49c0d81e29385762d85216eda29e5b10846091b8ad9d2d71674ee263ec48c2e6b0cbc95ea4ab2d66f43d1' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0x3a8fbd77b467636bd2e0f08174b7c51160106bc60ffd842e5c8f3bf568a762c64fa6ee1944eac0e46412712ffba34db08e5e' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xe17965d4f3ed7304f16dc675542813e2d6a126f9a429205bd03c3df37a189a3dec6a4cfda500dfecfd643866a7ba59b39b9c44fb1008b879ea85bfa414cece85223f16001c57c85a1bf5ffde7ea9ccf3b51d5706dabb6c0a1ed40974841dfadf331e' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xe28f10f773ab71b864cec049c036d339314c125bf3f9b42c88bad41abd0c99bd0ead51e0cadb256683e05518eba64e56cb2fa5f2427aa105f03a715a783a7a6d129f43c5ccb3fdf2bf0516ef07f9de0d51f03386435740bca9bda023ffbbe615a1eb' - tags: - - atomic - - uint - - wrong_length -- type: uint392 - valid: false - ssz: '0xe9780d7276f2b66e46e286ab3c522cc677dd57f74d36bb410821aae64450edaf18b3dd6b57469e449320e06295cdcfe49692c30d16b2c3f40f3f8717b97b6060fafb815cb3b78973f735f727f10ea4a1baea6ae35c0ff715bc2857278fd8ca8219d0' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0xa39de5e044bf78a4096927a069b5d4be00e60397bc8bfc2570' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0xb34930e3241977b4934603e622af76d290000546b8a4f54caa' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x0463a057e0206e1aed2186d0385be6a7b0e775e376b3158bdc' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x105215217bd0c475261d6e0d4c085b959ad0dabe2398de602ae9a492f09284dc8660f52331f5e9d600c178ab0594d3474d' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x320f82a0990bfe6b58f924f617a05f246ac601a8facadcb683cbd23bb70b043e6aaf23173e14ce521ce3066629176f7e66' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x06a9687fcaada8b72da45da616cdedee1496c812694e70722a7582083f3e27a0ea4384a99a91874f2061558d70ad6c595d' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x1380bb5255818b59940fc2547959e89d58e59110b3ef1cdaaadd910bb0143bad0298403c54c423b940547e88103e24e5f6df5c' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x9e7a9fd0ff5e9cb63017946a1f9b03dde416077f5bb0eeac55c450e62b17ed7f504d7173aee04dce08d98b832c014802d3bbca' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x86d7ca5fc7ce59dfc1ccf77b54f80d4f819e506a65664aec7a1b92b2398f5d4133cfe61b345de1f6efcba0557e1f4538b95615' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x3b70abc82f1cb97d37e1b403445af6579703544c2288c382fd91c1f163b45046116407fd85e57857dd192a6b643eecb8f3b5952972f19dddb9add0782686101019e479aedc56b7544f94c6269a93a82e1b1cda873aa244b90b0fab703bb76cbf5867327d' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0xa32acb4e0292a1260e205eb3ecc4045b7fe5bd30ebc8ddf1725a7ecb9322a0019fbb249f50011f2402856de64d55c407e98738bf1a3b0582c4734b873cb40a488c0667e7bfcce7e5c3b28160e2d1b18f98bd7dbd4e9acabecb814725aafa91cf78cecb1a' - tags: - - atomic - - uint - - wrong_length -- type: uint400 - valid: false - ssz: '0x1179cf97a395956fd7ae80c9d595b7cfe29d986580fd2eee465e468cde52b4dccea8ab4e0c129f899c8480fe086412129562ea65cc3480cf925fc2ae76e72fbba8db6a6660af88ba6532cff76ed8d069b01223d6c232e58e51c5612845f7f9ea73ce042d' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x5643108b4f6bfa32a8928fd9b4fda474a8eacad384bb5a3457' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0xf9da25401f5ec2664305dd13889160a175d3c427ffda243dd9' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0xd7474630d076c49e97e343d745af4936f218dd3f869aec9a70' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0xeb5ae2a04b4521b3323d0c8c0313ae46b51a0a0336fefefac94d46f8fe6f998ce4770c2759f7c3fc32b3a5aedc49ac3127a6' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x1492fbe369358da050550990df67084c0eaf71c2e8b8dc45e36d583f198dcdebe30249d8c88b29b3ef2bf0395c11aa52440d' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x1a3a7a62da6de3dd03306d3e18301dc0d0056798f52ac7a158d7f86f7d07592795b98d4dd7c85e8b8914b71b35aa7202393c' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x417c919381e1adbe772880a29ca80018a570ecec969537a3ee15a0690e05b5b4b6a78bb941884f5639a7be24ce4ce09c245aa1ab' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0xcd82f1163fc0afe142e07d1bd98fb804a188d9c3af4fdafd0b5cc304f3dbe6766ee9dcea6fa2a5752cc7917d4bd56855bb2d14db' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x0676f7cc0a886c2ba157d6159c46cf5b6f9e7ec539da97265ef52506ed8e9b1d1b91078908ced73843648ef53a524afb3eff2cb3' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x7840b5ddb28ad36ac5b0a34ab8e727a05a8f0fda5349c9772aef78c6ecaf10e571c57a85dfb28502e3557a913a68b29d3dd901c55f3ca81d99c6e7ad09d1393a92c5779cdf99569ffef8fdc84f19a3a0dfff17aca90332854c29ca8958dc88ddeb79685e0f37' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x1af705fd39912561f304da97fc7bcc4063fd5b3b278e926d980fcc9c9bdab2c6ca56ff7ecca2c0453ef6dfa7e82aef0cdeeca41d2c3e03fda444604af5838f092de8d546f61c2d39280cdfa12b056e3c36dd918152f156dcbb7962d82e275d9f3cce815c70e5' - tags: - - atomic - - uint - - wrong_length -- type: uint408 - valid: false - ssz: '0x4d3306d51404b7bc7b7ab4f74a488f97859669c94052b11c2882b363ee942fcb40add778b1c4210536d946f083cdee527aa6a440b02ff01cfa4298545bfe5ed68473ca39be87f292ee3d21cc6981e5e88ac3236498d51dcd5c6c37c88b0822129f85c9edb4a6' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x07e16279355d26114a6b33379178e8e2ba8b8ab7bb0fd2b3a202' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x0c573599886b9b64791f4a48d43b5cebb483c3ad9c6ab0cf7f70' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0xe8224625fe7e02448302b3082e34084bffa2c160bbd88916f8aa' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0xabeaf7a0109ac9e9a481a787325bc1d0d9706fb67c65d50e6593fe6d66aaabd00307f2be39d6c8acf206585846c01abda49638' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x31328904dfcd3c2e98b839bae2ca6bd053ce4ac895818417ce7f1dc15ac4c273306d0b8cf866384ea3148415369e0d566ba677' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x65a42c77008b4357c625c5d017796b5dbccdc8258f2009ccbd8010df35f69c048023dc97e0ba29482e950fb19bc7e60b8916e2' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x813b3269c4dec6120947ff50e445b735d2619b526ebeafd2eb0c50f1579f59e1c14f8c790705ce8d64b2f0d34fe17bfa300ac25d0c' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x476c17771fe5d814fdc101705160b220fd86bc195e01a6193a21a50a1cd9a978bbc90165e4b348b8e1e7b5f44ea9b6e25bebf57606' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x1ad90840ff72b2e30150b1adb3a3f6ef72050cf4ce242c6389639e21b8b0bec745ae472b9e61814c76967b183774cb00ef3872240a' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0x63c164d641c86af1e711204bc29570b8f88fd9ae8c12d86f6330ca564611da491f843daeab7829026c43a3ef9d97591553cdc7476530c7ae314a41b4669cbb510bbde27d412cd0755793ce2eeb317f56b2a42b9fccef6ff07719ad4d2e37007553ae2244691c8a90' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0xf2cd0f6b37dbfd716480d8571b8fff14d45fe1d10f06136129a9809dc78aa0b5aafce0b4b4f031f0ec780328b9f7d9a7c8ad2e16b8188243668baeb2452b0c9d69bd1bc520c641e74f4b7b463d7a6d9f132e0ff3853e5b12e5bf1b20c35f6bf7f7a3d733d2cb18a5' - tags: - - atomic - - uint - - wrong_length -- type: uint416 - valid: false - ssz: '0xa4a2d359919a04fa9da555ad095a1e0b10d04618e409e81b44d37845c0dfa2effc598a1b2260c9587d6545a9acd5d4c444d30844404d3d7e3981721549d72cda33afc5b58a3cbf81884f12e4e8e600b6d9cdb270081572f646c7987c1d54d0662da1d8dab0e59fa3' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x2f2cfb34b3218b61f4ce602bb55e3d142cbe199d5f01e1213411' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x6b10d41758b30a30e417510bf2bba6b700a2e8a5a3411d652d26' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x93267ddcad6f83eb6655de602156194f9b7b264a80f5ab8bbfe4' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0xb1a1d63332bf868c3cd01203d4b923541b942fa5344d5918338e8cf71fc96d75fb2a226c64b779d83bf64e98d8a82c06d1923244' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0xec38403b5316408f927287a8b8c08f254c4f24fc8dc6a6eb2fdf2f0d2fd36e7071fef02ee984d3c1d1704b8f7b60b0b7e379526a' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x6b26038f6a0f8d85d75ff739310e2673843f9b106f29631436a2ec447d84c64aecfeaccbe4faf6688368e08fd38a6073f15c7102' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x0ca2882ca235355c3fb1beb36b5ce1787540208767ca071c9c02c7f29d1cda1b861bea5940c4408b6a8ab87f1e0bfeaba4ac4291c5fa' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x2c7eb4f95cd54c6a7482908196b0f4d4bac9a32e260ac95565acde8337ec0ef6dc8c34e657de320a02624f6a92a5b440de57f4d1a31c' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0xd3f74a15cc272600baf3fa4ec6e9c3053d3a89967d41acca287f69024003938685857300095acf5f1daa46419d08bfea459b93da9e81' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x96c53a4e427d27ce4484f1678cc5dd753b8aed2e29627bb0e6a3b4617310ff0e0c9874efbbc4ca0388a49661ef366da2b1c8f0acf1b20856c799cfae0a378560782d14dab1a700b6000476800e9f2a308b85d9c1afee278020edef255c986bccf872fb3f13e69b47eea1' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x1855a068bed4215972a8a4d2335750fc6ba8491b74db5a16b8520cdaa0a3ff3356820f0a9082eef11bb305443901f71effcbead0b620bc84b1f9a2c156e6fa47c9fd4577518e01e417206f99e3902fccafd96132916258f498f5f4eb13ebdc8aacb29ecfe7a7d4972212' - tags: - - atomic - - uint - - wrong_length -- type: uint424 - valid: false - ssz: '0x08106d40ea26ea42296e7562470817a8690ff73559238683fdb561989c4d37da9ffcfb16b76c52eea89c3e9343c52bd4d09f692cc91f2edf5be6c65f71d1d7b28f3aba60753d3441439b13c03b30c5e98481de854e657b2137b8ef2419aa260c27a7d929471a15421e30' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x797996096226ad988bcb3deb668377d9794d058172e9e06f13007e' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0xa392821c90834b15970f92e2d33dd76cb9609a2352be59c9369ef7' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x77097901ccec17d174bc5865453c86f1bcbd955446457b4ca2ea2a' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x6ea8d16603b26ae0d3078de0098142e397c4e737c582cfb1ecbabdf4b641b2b8a63a854b4f4648e99b72f5b064667542b400be116d' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x86930750a7ef5542cfe861d09b11848c74e4b83f48b361e3ea668694951277267530b5d37aad2d58461b4bd92d1e0bffd703563bbd' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x65b0f9fe431c9c1882785e06022170b27fb56371859579ae1ec6627a7c6346701c58721ddecab4fcc8563832f40b56876b5b53d22c' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x35ef5b335913768230802310074c3fac9c582d04e66ad35cf9b6594e85fe0171f0f7f21f46d5203c9bc21e731c569c768c129551d46f5b' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x3aa75fa7e4fab71addb64c0102ae9c020d662f4087a1bcf3def4db65eecccae17aa2f4f7f57c2a3fa467bb07507a298acf2c7a0e0dc795' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x8bf4e250e1c14016995c72e7e401eb296a99f26723461faaeac15130eb7d345291372dc65c3a7c54c079dcf9bf082af6e11eeec6d2e930' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x27600ca26316063de2f56feae44d9f2d366295475d00229f0cbb71adeae7625921d1af045afc1f286b6f71ecd4bd9c88fb3f04ead6b224e528fec53e15008ca2df183d109ab1cd64da8741c8a11c97d544d951d296edad281f038921bd7991489c8e17fd3672f6694f3f0257' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0xcc3f1c498200459e29831412bbd2d01a660f5724d49f460cf4b8288552e2a1c23a8c344a81e3bca267671213c4e7d72c4ea9f5ed63f2189c0ce24d2523303e4929a637dfc2dcf65eae45d78d56ba294feec926d7bf104d0a3b3d1fd572e1e6f5234a172de440559b396636e4' - tags: - - atomic - - uint - - wrong_length -- type: uint432 - valid: false - ssz: '0x6d6db68d2a7e7673a586203d18a06c3559c81cef0f361d6fba89b99e7a581d43ad858b6bcc25b8e4dda135d9efc4b1f6992717b7bed14fa1814eb619cda092eb56414f37ca3b438586df5d5a8cd45bc428db16ea3a3e3df461452a48531f227465ea5a008368f9bba3c21a8f' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0xe1fb766ae91a0e4d32c6f38d8554a1e9b835eeba5340a2ea7fc399' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x7117ddd5fedf5e15a073f8784973ccf018120681d6192ca8d78019' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x19bf1e50b1fbb3a6566f52a6c0dd3fbb136e04df79ca8ba59ca178' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x49cae529bb297c96c6290699ec50d1e89bb753d23689b15c38f42fa1da6fd8d162d2d497cef1bd732d92db620cb077ed323afc5994ef' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x2b4860b282a2b651db5147994c5093539da93c94349fa63e4f87d4a040eb7bfa1b7d03a8f88ba5323aaf7e6b250897718d0c30c9a723' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0xe351b3f286ad12e279947ff3f788673e8e8e045e4f016f1d78429e4781df03393d9bbdb6062182fef250e114bce35ee1bd8ffa35314e' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x66eb67491c0788b6220cebd99f9b8be09c3cf791ab985b0e09dde30b1455e9e442d8ced7fd4c209f4493a6178a688fec62d1979cccc4d942' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0xdaf13404c6b60fc7e62d266e6f927ed9d440c670fa122a1bbc50eb3b24968d7caebec327ce97cfcd101301c6486a993879b91cc909ac968c' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0xf7828fb817942c5f40cc80f49faacb83137b3a780a9f799efc0e8f98603986448e4bc4ade698920884488f1d78109ef7b8616546db4acfc5' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x37e37776cf0a7e723fe45130285713fddb7ed6a3dd64dd00d07fbc481dafde0e45c4c9faf6b2b79a428b1808eddba9c332f19ccf167457cee94421db8a458970415cbf10df834ae44cd8c92e5ba305ed73b1b0b7c4d70deaf6b4c15e125430735c93d9f7c924438f4f8e9495b6fd' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0xa3144250b866fbc4ed72cf7ba973ebc44a05eab447ca215628a887b8870be38dfd70f73376f03da43b83ab1401e1b0a944e8d750260bbb2d5739827c71d812aff39f46bd62d661f5b70494bf87eac4c433cf363b4fc771f198e6b09625d7ac75fc92e06972378d4031aa2c86fb95' - tags: - - atomic - - uint - - wrong_length -- type: uint440 - valid: false - ssz: '0x3f9c23d43999ffea9579b92eb033f1e8d042b5705cca6948282358b407fc3e152900a9224470d0c7010d3efc57b7543ac343d62f5509524a6b8e4c82bb4e3e38e19e7283ec40f5f70e3c24eddaf2396cadebfffb4a385049283d05b298442b61a29b3a3cadd98cef3c7250741380' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0xc47e6ef3c9df63f641b208789b7ca913d121e75e6a0d64f75275f280' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x69be43f8d4ad49fc97761cb6439ecb454d7507aedbbff58aebb96b12' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x06bf94ad7729b1ae249b4ddce15ed757ecd1d8adf00608433399d204' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0xfcc8f6533d73d436d38e4acdb1e9cb3a5f54bcde16a285de352799324fb92c16a26eae756077e9080f08c4d062c7d21f3b29ddb7eaa358' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0xaf4c05d2826ae0c4e9707ef2ca826aaec19a425d464ab78f4d33fe6f47b549b3895131746814da0a413d1f8e308c77d1a936417834b77e' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x4e7a7712439743bad628142a9f98b439085cb7b803636268c69a4df5dc7c0f7e77dc8553318c538b27c4b73dd0949b7e595903098c3070' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x7d9c73896c5fbff9c772761298e3bec367dfa176a3ec4430702f6a8628b99d7f93f24a34481f2e2e9588db1f2c19462e915f810d089d030baf' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x590a41ad4d6c090e9fd1c4dbac5927041c73e9f3e854d91131b2ed2d8ceb9926489eac8896cb1949fa4a82d55db80f223fb65c022ab9d9fe4d' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x9ddb8590197f1a44a37468bfa23bb43bebab99c246507eeca9b486fa50cb717e75a5caa62f401da14a5c91d72aa617114d192bb30ff0b30670' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x515c528cdfe319920840a2b4c0f2e844cc36aaf9f8fc2d8379c658c1df32b7de0f3ec0a87eebf23016df38cb69d9440d44f4459c81c8e706ae95afff173b1c3fdaa5f8fd9cf10acadac0fa02c4ce78fb358cfe55ad0d9beb10f17bb109f8effcde7a697476ef916433c40815738556ae' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0x9cf6dd551996e64112c987919ec618e8bfa059fd20abb5cf0f6e30d3c570f250a42adfb045fc821a3bfe0cad4195f1d685a2c9ffbe3a647043c0c5c880110d20cdf2a2bb43680ef401b373799f6841633edaf9f42357978499e85edbaa24ab9c4083f93f4f5a53a6f1e895cfcb501351' - tags: - - atomic - - uint - - wrong_length -- type: uint448 - valid: false - ssz: '0xa78c711dffcc66abffcac5c37345b7211d657ae51f3f1a582328c8f3bf9825c08368f0626390cf1f20b8045cc4805bf46ddce9acd8133b42f84ea21cce3f8d15d3871b447952344b634dbf95ecaef9c67b7b858c4f20589d48032f772e8b6f6676b9b8b7345a630685825f238f8d0c92' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x3bd28a1b39ee6abcf6942ac673a69998dc96d7c1fe9bc8fb865aadce' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xf8d532629663af4c4aaeec263d8469505f379b29ac15763d339606de' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xc16da2c7c38a202ef7085583239c232d3aa132bc4748d56a71b9cc2d' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x99a037074645bef0275a257258476dbf23dc48444595b162f17e4c951cb4178b592ef34f453b5d679252d8c191fa53aa87c0a7b09f10e8ac' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x4552bb17eef618be0270ce796672f9f6ca66ffa49ad9b707a9c1237e7b9ce3027acca367b7b037baae12da486e7fde5f7515cad246ddb082' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xbf6de95166a59e0cd503bd970e1b88f6615a8be0dd3e594c35fdb03b798c1c9697356236624c4b46b121f7f034dcd99ff8537dcabc4daff4' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xb72fa75d18f93ba9b0bbdffa282b58ce46013f76f239458b3cda622b6be15f14fc79172de2e58cc5de91fdf56d9b6bbbb013aebe1ea88f3cfd24' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xbeb8398003068bffca90880f45c4eb5052f5008c169d26aaecb144d6fe67a3c1ec4a12a67c7cc3461c646167ecce1ea2b4dd6e7f0214f41c17a7' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x319fc2c6c021418861d8ca06a5e4efa4aa4da3ad5fd40c6b14382ee8875a681051d8bba6d9dcd37f1feaa8cc3f43a40495b4de2f075d911c8ec3' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0xbcaa468aa842a72c0f1fb3e28a0ba03ffb879e42a560ce5a54912651ea816ff15493e7a0f864ab1d0d9d646ad51903bb947f0ab86b87c31a38e5e8ba1317eb13ccaccb1f964c3b18fbe85c54ce1a9144f5496c382a928a0d3d08c25f6cac48b3dc2ea65aa8eeb0fb5fdf0eb9a2fd6686131b' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x6d1d53db83bf44293f93ee429af4316ec3157e487250c353ef351fc22942b4d74bd79860b93ebb3135c3f6157a9a2cfdff04d9045752ae99a395ae6a66525f9117830d27160206648005991c6cabb1a10e441f63e9c1ab8d087956e090a5b83bc41ea51f64e40b7262195f66c09b7bc4e59f' - tags: - - atomic - - uint - - wrong_length -- type: uint456 - valid: false - ssz: '0x82a7a3b28fee35e6f2cc68a033c47d4ebba910328e3d76141c330e77f7c87b45c7dbcf87c770a929fd703296357de9ac6d9bfde4bc4a57cd43cc7372df0768c567bd34e14fa163a462bf48c80b54d98ef0d7b0cf834a457dac2f7aa11f951fc06e52a2d69124e1482ad50d1e4d2af1a20e75' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x914361ed8b919c49c9dbfaa8ea3cf26141a1629e42fe5109dd9f01b5c2' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0xa72eaa122d64b56a712503488f1b5a0a91fb1eec85a794fbf50831cfbe' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x7df1fd46f7e4bf301a6a5644f732f54c03521e10cfbe574f340544b082' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0xff1aa190946170b2c883f5e1688b4352fa2f2b8db05295acdefb3fd4b7dbe73078a98058e874f9225b4712f7c95dfe3e5cd5f9b9366ce3aa9a' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x5c47cf9c6af4d94b45223929507bed091a1c668d2ab568890b906dbea393ee9ffee4eefd685d8b1f1ee75fd1df6c4a995354676ab576a3f9af' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x69ecdffe8224525f5c4ee53391c0dd64cb61fecc3a767da83b7637aca8a9d2f3a2946e7568f035bb39823ab7fce6379dca76835a28ce33b8ee' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x43c9ab4aa8b733367045f1be2e3dc7e91201d7d74f51dff43db625d97e16cec6bedbf69fe740c79d3d905e0d8e92d004a287d97a8208c2e1b5799d' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0xdfa1be337da8598eb00fbaee9b9b98aafc4ff18e6de0d5e5047a8d92a59c92db309a7ee553e99bbbe9ff6f0f19c572098ed365c21bc6bbae70d9d3' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x0d61caaaa9f785e052c4ef40346257f94594bc0244c29adaad48d0aa4265a4589055d515bb3bc6443316002624b034be4beb6f370cd9ee138a91eb' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0x6675b8f5222e78d0bb9819afc80bc3582c438c877dcea2150390cdef1feab6fb2bfb6383e15c4f38cb1cf6f5ef3e942cca8b608328ebd72ddf66d6a22d6e0efb367a8354ce894c095027c7f774578fb1d05b6ee6407eebaaca5966f29e202e5e9067e58705b6bf3012c23305240e3f523319f3e0' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0xcf45b8cc1a22f75d54c115df03b349a506e3b0dbf5944994e323a6cb4450bf068a291af07120575e305f0c7a63d7c1527e588f7c23447d79901b304fe890686a41c12bfcb45306d7a1f52ff5caae1556c8331ade64741a238e91bbb2754af824c83bea21afcd1201ab53c17b0ccb772eb509ae8b' - tags: - - atomic - - uint - - wrong_length -- type: uint464 - valid: false - ssz: '0xac727ed76133746314d964fa5231cad9ed1c786658a7296aa6b52af857e246c604cd455b606fa9a9f2726c6accfdc22ebbdc0d16a91caa6573ba22e7aaf529142a6a5b3e9c74fcb34ff686eff323f370c5837d680e9b3b80f9280de57ec9da6b3a0c1fbbfd24ac721f60b045e4b75c4e8a2b60fe' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xb8f01d60dc17cc31fa92986d231f3255a33c8233645073dd2a31db7c00' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x7aa9c98e1cf238193703aff0d196ec3b7a410bfa7caef6b294c46ecd26' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xa84bc042bc4487556363659c6afc5ca0d7677861407b5d318f93095c79' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xc4a1ed55699847ad0d7a06dfbcaf78c54845b499d9d83b956123b57abec78d319dce9de992794e56f38a6486bcb9530c0aeae03ffaddb9e5cb59' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x20c00a150c2221bd19e7500ec6c7b881cb2e87ad1848d1415eaf1c2fbc6375c2e086d1a87f37c95ea42dca07c88da494654afd784a575fa66d84' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x33dea01faa230910910e413814d61ec2999710671863904ba73bcb4f0878ddc4acad7b9f5ee2f79deb92cb6ba37f0a851624e71b9212e073740f' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x00b1dee44a6cce3577fd05495edb4dee2e5032ed0b4d45fcb77318e2c7470cdfb3aad7f95003eda886e7be8472c98b1ebe8afdb9f824f274dee88904' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xffd36e846b5cd809d34ef042ab106d439a71a30a33c3131dac83303f54cad5762817cae9c8b1e061ead2cbbe618764cd601ed8f63176a8b5de81de95' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x7886f091ba3031064590d9c02137054cf22d7f07a4ee840738246b5d4ab5d64dd4daf2667d05d9466d72f6881067536d03ac0374852568736b788fb0' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0x922b062ef34f0538f56474a126557d52b8184e0b1b1e3cc2e74a7a636e1873184bd1b51bee81522f6912da201c5d099c14aec56cfc782e2b473729045d21e9e77fbc0c804b16d6215e738ae0ac1e3951dd670ae129b2e1b3f92cf6851f2da010e43b49d542224998f099ec46891976edf2dce87bd423' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xea0d96ed14b5c9d6e2ca6179bdb5afb91097b857d2b7c3cd191ff9296ec2c4e36a7f9dba1d88fcf0f85ff7689030978b27d431ce3b249b0c7e3ec6ba324ff64bddcfe0d0e914c6cd6efee7143e28b1c2b942f16d27d1edd7bac91f060f6c8afaaaab462242e09d0d93fcb7664553a2ef0b7bf855f8ce' - tags: - - atomic - - uint - - wrong_length -- type: uint472 - valid: false - ssz: '0xf9d8ee7b3ccc5f2db9b6290a2fee89658700f2e59492f1058e67205f200a50bfd5257649d84b8e7b4a9b14a88ea9ca6e63dda6618880fb7e64632c32e62b0a2c9d539ecc836a42aceef54e2fcb13f468f4a09c4e67b36e012253b453a7ac9cee2da42cbe058c42f010f945d2010ef965a490981983c0' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x88d8d00aa6036baeda19e05ebcab21815a52c2a8d91642dc16b07cd5238c' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x9dd2aa41217ba3598280adb946272c979d75a14bb4a79bc37e1d97a94603' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x6d1ccea052aabaa28af1ac22a0cbafc26f84700607f2ee8ba88862c8ddfc' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x32471058b2b56dda87b15b7aae8fbe113d25c99abd3d9cd5c890d4c634f663dae24b99cfe7a1e7895bb400cff53d845c1fad09be544a158ef814a8' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x653dc7fbc71a4f70d57f155ac5116776ad54e997ab4b92acd33b787c88039b6182d426d6980b8f4d20d705a3ebbc0ca33e6e3c5a52512da7cd1b58' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0xb8a9c8c83df495abbdc5586148ea46adc9b3624c51b65ffed5e4b2b070b172e9904e740185f2883497fb7c4718ddf4a91cd02c2944b6f59acd5fd7' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x80cdc3b66a89179e1b51853e03c1cc30831e8cab0f830c025ba80ac6de38e74a83e2d0cefce86f550d58eb4504ad9e390a56a4ec4d8b4445454eb21333' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x6991054a30ea2d12e2915539ab83680e58ca3a7a046309e803c49f8826637d46dad4495da7b32d41a0e582d3ffdaeeda3e5ff576daca1854fc143aae66' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x84b7a287f508c3382610124822b5343b27a4ac3872a52e444e109162bdb518ffb95e565a908d2347d74686a61d0aab1fc049b64a86f14d429aca163574' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x860e441ab45e00dd0b73f762d90657d543ad7fefc1165161207872aa2c565d0ada3a1d479550b3e73464aef019663010dd2ce6b3d34c07c2772eaf78e6a150eb638cfab0737b66e36d8cbd750d0455d28d6961eb4d3366c9ec9a5bac51823f14ab2f6e0f17195514cdfbaf33f5596eea8dea96896e795bc4' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0x97aa14459f0cf84c9d56c56340db0d8c55839a11431e3b5b9a30308768ee846f1b696f2575bfa541d5fb9f548fc68e3c8ee6c70ebf638b0b95e08e85b705a651f125034463cfad7b945ba42f9469bf336a0008e59a66bf5cbf65d7c29c85518c552f2ff5f4e897d62b45397b63e57fd43be6193eb52369ff' - tags: - - atomic - - uint - - wrong_length -- type: uint480 - valid: false - ssz: '0xdd614c709ebdf9401a274a68ab50ca0cc86bc0bae02057f6e26d65fe30fc1dd46c8b1d0e95bd2ec4ebc7071d9360d7d635b4f53798c1759936ca84a100a8644c6b029693b1006df1d89112c3dbf2fb1c017a905ea313ef78b4a6a711df72ed6c1f2910800f2f99be43e6d55f5acaecdcc82e414468f250f1' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x2c1ae969495415d40601e573be6d7c60248a232ee6124cb350ad146b24f4' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x857ed937c0c071a5932336e069f6ef956e3bd6ef1a8c7fe2571a9387dfb0' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x589d2ce2c90dae0563a8e55a3947b0cd82375060214c23f299670c97020b' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x103010b6dafd70521d8b4984a190b1f0473e52e29cf7674d07aaa015eb8051767b16f078f1bde0edde3d4afca5287ccc69180471d52c9f53642f1ab9' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x485b750294e6f59ddf6bf3ccd552743325ca45a17454d722cda90a242a9901d57d63c0aaec3d427bfba1295304d9e68188eb5a3d02b5f6f0b26e8447' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0xd35f5825af775419035a5f901ad71f413d3a6abd4157a9818f044c9ba96aea588d529e69816469b2e00ce7481cd3b3137bcf7fce1e27e96e4c3669cf' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x9dae99e7aed4eb5e0f1c1f182f4d2b6140b0f4ddfac1f99fb89f653e25b9cbbe2c001925d90e529d0e0e0a82eb94b547a22cddbf1146c964ec6aba461272' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0xe683eff4c7d01b9ebbc4925e883d22405c307cc75b094245e29ff22743ff1af293001b306b263df2ad19e6b6a73b182c5fc8ab3bbfeb319470507c99f43f' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x56e567f860b545cf5c4f7e5f80b66b2e060ac81548abac4d5e7c63467e163954b9a2104d46c952c6e9dd10b1de40331deede056be19115dbe515e4d63d11' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0xebbbcf9c993304b455fb0ef360675e85b591dbcfdc8a29b91f818c2f00c3a90410ac32ca6998e0e030eaf3bc9f321aa21751849d894813bea316250ab8ac1b4292ef6dd5a365a358f84d000af041828deaa1b3d58083abe6b60fc4f30e1f757424a6b33c94003e340bc1081c67b83979859f6f635fcf69fe22f3' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x0e0794756b94f207cb13c1359c8203bb082d8477cd740d166f82d01edfb1b124b40d86986701682826d3256be45f9f21b4a08945ab8f71b0ba2788aa14c6aac6f6a1f37eeecdb980e509e164d9d832400d0f7b42ace1bb6b51344fa656e342449a8da37b37bc7fbfb33a815fd4627d239d20d5c4f6876cc65d87' - tags: - - atomic - - uint - - wrong_length -- type: uint488 - valid: false - ssz: '0x3d26084e33e1fa61de4259cc7dccfd5bb6db7aa5e7a80d24742d3cfe4c889aa716ace6b037898ce3a8e5fa622de76674b6b335995f89ac8f435a597ac594d6bbc27e3e37f7f62eca1cad16a351a35ffb5f30b7952e9587db74b76aa7f59a6a6a82d90b445c0641f5764dac34aef4385aba7aa803eb173469a932' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x9ef4c9ff14dcf2731c42c7eafd0b184f143dc2c83dcde12a7bea151cc4b51a' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x08b153782f6bb18623ceab623b78746acd7528a37bdac86fbece4abc1d685f' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x1841573ce1e9288ba545abc528b49c08e4229025673f49a19eed5496a172d8' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0xaa5ee7dafb07ba33337b1f510a1cf5eeddc88851159939867f134f879ad5fc8e828ce2f735190a06901ae1b742b722deafbe2a91825f461994432a8db4' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x96f50f3fdf375986ee04561dfe7bb709727352c7f9ddea2a58b582e131c9781bb20e59053c19b390862c1f1726e1a9c546952bb633a3c6871fb300eefc' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0xe34c5d22b1289367b1fc9b1d81c9eedc349c0447aa71a840fc8323f81c8f6820104a6192276d045efc85950215564d56685c070511aa9dffac14ee8ce6' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x46e7c618125004bb0874f1ab1c50ef7460108abc9745a8cd984f35999b899afd2fd62e1a540088083e594a502df0eaac36328b1953bdc750a80425d504f8e3' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x8eda7950b9677d015e16b5875da6e0c4d8a87fb3cb2d2833f376a5faa3610126227ce981dd64dc01796f6d01e387bf6d45109443ecadd82c1d78703cb46a8d' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x6e747676053fbe1cb13da5863fa81e1c9799908320d09063b3c2ecbf9c3880845b2365dc41fc579e3c2874b7819fce10ad45a690afe3e969e3df52be5138f7' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0xe2a7ce717907d3e02c7dd97efd4e50753c366c9d0f9cf33a0fcf81c1d2f184e1b649a88c16b239e21ad86d047a78e701b0d19899364fb168012fc164710ec4b74b613359630bb6bfdb75140f365e1da8e3327295d2d51f88e5c932f4cc53c23eaa70cc24865ab9d2df0bd93ac5c0a51a0e441a202c45f25207d457b9' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x0624561c85a3c3f5d69f9e5489e7ac65c422dc191a003f45780b3036ae03d32d345d28ca65ad5a261e7149f59d23ccc8f362915df2146fa0694dc76461ae6ea6df9cb467cb8f9932d94435ade1e9416b66c415583eff9b5417792206d74e779a06a7a8db5eb827102d13994cd12fcc9b28db23c3ec1b89a677f31922' - tags: - - atomic - - uint - - wrong_length -- type: uint496 - valid: false - ssz: '0x0c1a2f8070d047c502d87968c3fa2bd5ef096f89a3133110dbffef48d388584e3a85104326cc3ed77a337bab6cdac8c66cfe06e19b740aff1e56ce9a14472a100a25e86e46121dfd43e309006be59c047747e1c8b4342985754e524bb5e562abb33e3215f14734677f5e979eb8dbd3237b409b986a75ccdea1490115' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x90738be8108c86c80cd6a1bf7ae6093ce3fe17a19b13b9e161de4a30341510' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xacb7263816aa75ced357500ca9fa1f72ce94633ac5382b211b161e0df04eb9' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x04e869da86c9b97cbf55c65df14afc41f5e7dc0997d96c3f1a695747066c5f' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x7223b4131b39cd6c629a49db5a7e17d5ccf060f9ef543f6626a2e6dc3b423d9f9606037903cbc062c1b75970d021693c638d9952e3c5c463ab63a8892314' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x720e906e8abc6ccb4ec34b773c634606a7cfcec66b2eedf4335974fbcce49ab1d70d396bf99650a5f4f4955fabfcf3542cc755c581f3cca5f758ed6f14bf' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xd5293ea27b35ea5930de4cfe4a0ce16443ec87a7058ce48283acb720c9e43c3a0d4dfca2c2dc04bc5f13c0479a23c9e618f40aaf48151ea3b6a3d0d21dbe' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x2f5c857ed43fe5ccbbe5bb4801f02551f51bd90482a249d37a31104e7e3fe2932c74f273f96f37b67dc97c2b5666f9f56e7b1a4ac3bffff593de8a280d32fc19' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xa5e584da5152e494b7f516c41dd5b5eb08166b438090cbf1f54539ce3fc6ef3b9b411c59763abbfcb1a8a997a81116a089ba3ece4a76f8037047fde945af5b3d' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xe3a07092b4efe0bf62b9bf9a040c1e5dca8708a2f7b162adffff5b27ec293755a80fd71faa9cb647e8a44b23ff9c894cb00156a8aee91b457390678dbf38a5a6' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0x1179279087af84216d885bcefd46f24beb0750d6e1dcff9bf91f5cdc773d33d4e8ee5318781dc952d6d5a3c37e75542e22ac364aa087330e6dc0d8d5cd77e0bc430c6239d132779f520df791c399e0aa2b2ba2575f6ab2aab4658f0cb83abb806a4fa2caf69815ab16d6b848daedf0c4995b4baa0cb5a06587ecf5e0ef56' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xda1d320b32fa93a1937b72b8a51bd93ec118da946b715f6ee74957ea36cdea8297bd3347155399d7675634784f062a808ac957dc05d0b9a608341caca5a091e822f4d001e11ffd157c134de90ef4cad57871e067eb47057904d51c1b630ea0536e764080b768879d4d7db0b6e4b085405b3982d6cdb69755a4d572d7ca24' - tags: - - atomic - - uint - - wrong_length -- type: uint504 - valid: false - ssz: '0xb1a8d2b87426704af830ecdf8613f3df21f1cd6839859df7842042c7bed4809745d2f047da1fa177c1edfc0195908b50731637d326d5b50e56eed54e60095880ec9f73d311214d3d04674495f2b9e24fd724eed40abead71767374c0152dd3a24548b96c6726c2d3d5a386708302aac65d698a270a9cf5259dfe75cfc1b9' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: 0x - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x1d177ceeb995de8d0d71a521ccc893ebdcfc26fbfb945b20d80273623c8fc32a' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x4e02ea3b4dc3e64d8923410db1c810cb700d7c6c89892c7b783113c290ca5b35' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0xff1bfa097ffb1fcbe33c23809144f7e3e1c20e447f555d63cc2e1187bc916d8d' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x6e216a137acd8cd14a86269b3da22a02d1b94405b1ddd8bc47e51d32d353b9355f490cf821fe1bad91f01b020b122ee2810f102d5219846c228d8f8cbc7e1a' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x8f936f8bd5052680b061481e7d75ee916e670d68fe2e792f3a02bf2b7dae2dd52434d46c9a436109fc7ed8a4629e2f354c342d3895189215cd1e9b1de180eb' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x59a79108d5c925a7262163db635f283a195b7eaa2924dfd110ffd7f2f24668585641b146b9bd93bcb89b835e3583ec9c6696ec11e46ef1cdfebf47d3b2181f' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x679503f23962d8334d03a92cdee75db2b244d80f0d5d372d564789be0149bd964bf6e1f1abe6adb7b8e2dc0af930932b7fb20629fa0f8c6e4c7aeffc25b630402f' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0xd9e94ee316cd361b98334a03f6558d478d6d92bbeeb5ce2b1bfd3beb120f203e98b8e5a9592ef9ac7e5a8176632a4721052d60269c04cf40f49a374d4c2ae0a954' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x980d12dd06e63119756a3d13b3353e64d22ebb3a117cc50c20ce16507bb3cbd295947eb72278c61ef83e9b1acfea110fa1230dedcd90ede7c21b0cd4324a70ed83' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x1ed02bb4a5bc8d57fd1f6f416f4207d2fd6778bf1fe1a505ee54f9d7bda3cab67360a263360d04cc6dfcc2e7587e50a0e8298069e8904acb302b7ea5a12588dff6f32fb950019d554f58697d09f1555d74800530450b0fae1008ce1e92e32458d43c3bfb58e2753b0439ab0ceec66daa407af154f20b714f24207cef9f664838' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0xb472aa195c472b7210ec7668c40041d818d590007148183972e04cf2cd274528c7b766ac6889ff54008f920ac27b5ff576514f87558217fb94b9494919d795386e4492366288ab5d8fbb4a4bbaf6e27a6c9d994fc9be726a6c50762cc37e3d454d2dce087172586f7e861bd2d5066a76c92e41e923d51e01746798ca0e50757a' - tags: - - atomic - - uint - - wrong_length -- type: uint512 - valid: false - ssz: '0x88807daec4c1bc6698d6baa6663069709b54638406682db48b2736c38332b2efc40eb6963fa438d62f359926f390c0936b4c225693a1f3b25d01a01eead62192b3cac5256452f13cf96e451d5edb873bdd6044e8323187280a6de9c8f525399492bdada618e1eb7226586b488d32d14f335ddb3247cc311785c26510e282f52f' - tags: - - atomic - - uint - - wrong_length diff --git a/eth2/utils/ssz/src/tree_hash.rs b/eth2/utils/ssz/src/tree_hash.rs deleted file mode 100644 index 85e56924c..000000000 --- a/eth2/utils/ssz/src/tree_hash.rs +++ /dev/null @@ -1,107 +0,0 @@ -use hashing::hash; - -const BYTES_PER_CHUNK: usize = 32; -const HASHSIZE: usize = 32; - -pub trait TreeHash { - fn hash_tree_root(&self) -> Vec; -} - -/// Returns a 32 byte hash of 'list' - a vector of byte vectors. -/// Note that this will consume 'list'. -pub fn merkle_hash(list: &mut Vec>) -> Vec { - // flatten list - let mut chunkz = list_to_blob(list); - - // get data_len as bytes. It will hashed will the merkle root - let mut datalen = list.len().to_le_bytes().to_vec(); - zpad(&mut datalen, 32); - - // merklelize - while chunkz.len() > HASHSIZE { - let mut new_chunkz: Vec = Vec::new(); - - for two_chunks in chunkz.chunks(BYTES_PER_CHUNK * 2) { - // Hash two chuncks together - new_chunkz.append(&mut hash(two_chunks)); - } - - chunkz = new_chunkz; - } - - chunkz.append(&mut datalen); - hash(&chunkz) -} - -fn list_to_blob(list: &mut Vec>) -> Vec { - // pack - fit as many many items per chunk as we can and then - // right pad to BYTES_PER_CHUNCK - let (items_per_chunk, chunk_count) = if list.is_empty() { - (1, 1) - } else { - let items_per_chunk = BYTES_PER_CHUNK / list[0].len(); - let chunk_count = list.len() / items_per_chunk; - (items_per_chunk, chunk_count) - }; - - let mut chunkz = Vec::new(); - if list.is_empty() { - // handle and empty list - chunkz.append(&mut vec![0; BYTES_PER_CHUNK * 2]); - } else if list[0].len() <= BYTES_PER_CHUNK { - // just create a blob here; we'll divide into - // chunked slices when we merklize - let mut chunk = Vec::with_capacity(BYTES_PER_CHUNK); - let mut item_count_in_chunk = 0; - chunkz.reserve(chunk_count * BYTES_PER_CHUNK); - for item in list.iter_mut() { - item_count_in_chunk += 1; - chunk.append(item); - - // completed chunk? - if item_count_in_chunk == items_per_chunk { - zpad(&mut chunk, BYTES_PER_CHUNK); - chunkz.append(&mut chunk); - item_count_in_chunk = 0; - } - } - - // left-over uncompleted chunk? - if item_count_in_chunk != 0 { - zpad(&mut chunk, BYTES_PER_CHUNK); - chunkz.append(&mut chunk); - } - } - - // extend the number of chunks to a power of two if necessary - if !chunk_count.is_power_of_two() { - let zero_chunks_count = chunk_count.next_power_of_two() - chunk_count; - chunkz.append(&mut vec![0; zero_chunks_count * BYTES_PER_CHUNK]); - } - - chunkz -} - -/// right pads with zeros making 'bytes' 'size' in length -fn zpad(bytes: &mut Vec, size: usize) { - if bytes.len() < size { - bytes.resize(size, 0); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_merkle_hash() { - let data1 = vec![1; 32]; - let data2 = vec![2; 32]; - let data3 = vec![3; 32]; - let mut list = vec![data1, data2, data3]; - let result = merkle_hash(&mut list); - - //note: should test againt a known test hash value - assert_eq!(HASHSIZE, result.len()); - } -} diff --git a/eth2/utils/ssz/tests/tests.rs b/eth2/utils/ssz/tests/tests.rs new file mode 100644 index 000000000..ed318d924 --- /dev/null +++ b/eth2/utils/ssz/tests/tests.rs @@ -0,0 +1,288 @@ +use ethereum_types::H256; +use ssz::{Decode, DecodeError, Encode}; +use ssz_derive::{Decode, Encode}; + +mod round_trip { + use super::*; + + fn round_trip(items: Vec) { + for item in items { + let encoded = &item.as_ssz_bytes(); + assert_eq!(T::from_ssz_bytes(&encoded), Ok(item)); + } + } + + #[test] + fn bool() { + let items: Vec = vec![true, false]; + + round_trip(items); + } + + #[test] + fn u8_array_4() { + let items: Vec<[u8; 4]> = vec![[0, 0, 0, 0], [1, 0, 0, 0], [1, 2, 3, 4], [1, 2, 0, 4]]; + + round_trip(items); + } + + #[test] + fn h256() { + let items: Vec = vec![H256::zero(), H256::from([1; 32]), H256::random()]; + + round_trip(items); + } + + #[test] + fn vec_of_h256() { + let items: Vec> = vec![ + vec![], + vec![H256::zero(), H256::from([1; 32]), H256::random()], + ]; + + round_trip(items); + } + + #[test] + fn vec_u16() { + let items: Vec> = vec![ + vec![], + vec![255], + vec![0, 1, 2], + vec![100; 64], + vec![255, 0, 255], + ]; + + round_trip(items); + } + + #[test] + fn vec_of_vec_u16() { + let items: Vec>> = vec![ + vec![], + vec![vec![]], + vec![vec![1, 2, 3]], + vec![vec![], vec![]], + vec![vec![], vec![1, 2, 3]], + vec![vec![1, 2, 3], vec![1, 2, 3]], + vec![vec![1, 2, 3], vec![], vec![1, 2, 3]], + vec![vec![], vec![], vec![1, 2, 3]], + vec![vec![], vec![1], vec![1, 2, 3]], + vec![vec![], vec![1], vec![1, 2, 3]], + ]; + + round_trip(items); + } + + #[derive(Debug, PartialEq, Encode, Decode)] + struct FixedLen { + a: u16, + b: u64, + c: u32, + } + + #[test] + fn fixed_len_struct_encoding() { + let items: Vec = vec![ + FixedLen { a: 0, b: 0, c: 0 }, + FixedLen { a: 1, b: 1, c: 1 }, + FixedLen { a: 1, b: 0, c: 1 }, + ]; + + let expected_encodings = vec![ + // | u16--| u64----------------------------| u32----------| + vec![00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00], + vec![01, 00, 01, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00], + vec![01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00], + ]; + + for i in 0..items.len() { + assert_eq!( + items[i].as_ssz_bytes(), + expected_encodings[i], + "Failed on {}", + i + ); + } + } + + #[test] + fn fixed_len_excess_bytes() { + let fixed = FixedLen { a: 1, b: 2, c: 3 }; + + let mut bytes = fixed.as_ssz_bytes(); + bytes.append(&mut vec![0]); + + assert_eq!( + FixedLen::from_ssz_bytes(&bytes), + Err(DecodeError::InvalidByteLength { + len: 15, + expected: 14, + }) + ); + } + + #[test] + fn vec_of_fixed_len_struct() { + let items: Vec = vec![ + FixedLen { a: 0, b: 0, c: 0 }, + FixedLen { a: 1, b: 1, c: 1 }, + FixedLen { a: 1, b: 0, c: 1 }, + ]; + + round_trip(items); + } + + #[derive(Debug, PartialEq, Encode, Decode)] + struct VariableLen { + a: u16, + b: Vec, + c: u32, + } + + #[test] + fn offset_into_fixed_bytes() { + let bytes = vec![ + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // | offset | u32 | variable + 01, 00, 09, 00, 00, 00, 01, 00, 00, 00, 00, 00, 01, 00, 02, 00, + ]; + + assert_eq!( + VariableLen::from_ssz_bytes(&bytes), + Err(DecodeError::OutOfBoundsByte { i: 9 }) + ); + } + + #[test] + fn variable_len_excess_bytes() { + let variable = VariableLen { + a: 1, + b: vec![2], + c: 3, + }; + + let mut bytes = variable.as_ssz_bytes(); + bytes.append(&mut vec![0]); + + // The error message triggered is not so helpful, it's caught by a side-effect. Just + // checking there is _some_ error is fine. + assert!(VariableLen::from_ssz_bytes(&bytes).is_err()); + } + + #[test] + fn first_offset_skips_byte() { + let bytes = vec![ + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // | offset | u32 | variable + 01, 00, 11, 00, 00, 00, 01, 00, 00, 00, 00, 00, 01, 00, 02, 00, + ]; + + assert_eq!( + VariableLen::from_ssz_bytes(&bytes), + Err(DecodeError::OutOfBoundsByte { i: 11 }) + ); + } + + #[test] + fn variable_len_struct_encoding() { + let items: Vec = vec![ + VariableLen { + a: 0, + b: vec![], + c: 0, + }, + VariableLen { + a: 1, + b: vec![0], + c: 1, + }, + VariableLen { + a: 1, + b: vec![0, 1, 2], + c: 1, + }, + ]; + + let expected_encodings = vec![ + // 00..................................09 + // | u16--| vec offset-----| u32------------| vec payload --------| + vec![00, 00, 10, 00, 00, 00, 00, 00, 00, 00], + vec![01, 00, 10, 00, 00, 00, 01, 00, 00, 00, 00, 00], + vec![ + 01, 00, 10, 00, 00, 00, 01, 00, 00, 00, 00, 00, 01, 00, 02, 00, + ], + ]; + + for i in 0..items.len() { + assert_eq!( + items[i].as_ssz_bytes(), + expected_encodings[i], + "Failed on {}", + i + ); + } + } + + #[test] + fn vec_of_variable_len_struct() { + let items: Vec = vec![ + VariableLen { + a: 0, + b: vec![], + c: 0, + }, + VariableLen { + a: 255, + b: vec![0, 1, 2, 3], + c: 99, + }, + VariableLen { + a: 255, + b: vec![0], + c: 99, + }, + VariableLen { + a: 50, + b: vec![0], + c: 0, + }, + ]; + + round_trip(items); + } + + #[derive(Debug, PartialEq, Encode, Decode)] + struct ThreeVariableLen { + a: u16, + b: Vec, + c: Vec, + d: Vec, + } + + #[test] + fn three_variable_len() { + let vec: Vec = vec![ThreeVariableLen { + a: 42, + b: vec![0], + c: vec![1], + d: vec![2], + }]; + + round_trip(vec); + } + + #[test] + fn offsets_decreasing() { + let bytes = vec![ + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // | offset | ofset | offset | variable + 01, 00, 14, 00, 00, 00, 15, 00, 00, 00, 14, 00, 00, 00, 00, 00, + ]; + + assert_eq!( + ThreeVariableLen::from_ssz_bytes(&bytes), + Err(DecodeError::OutOfBoundsByte { i: 14 }) + ); + } +} diff --git a/eth2/utils/ssz_derive/src/lib.rs b/eth2/utils/ssz_derive/src/lib.rs index ce2538785..ef6e2440f 100644 --- a/eth2/utils/ssz_derive/src/lib.rs +++ b/eth2/utils/ssz_derive/src/lib.rs @@ -1,61 +1,11 @@ -//! Provides the following procedural derive macros: -//! -//! - `#[derive(Encode)]` -//! - `#[derive(Decode)]` -//! - `#[derive(TreeHash)]` -//! -//! These macros provide SSZ encoding/decoding for a `struct`. Fields are encoded/decoded in the -//! order they are defined. -//! -//! Presently, only `structs` with named fields are supported. `enum`s and tuple-structs are -//! unsupported. -//! -//! Example: -//! ``` -//! use ssz::{ssz_encode, Decodable}; -//! use ssz_derive::{Encode, Decode}; -//! -//! #[derive(Encode, Decode)] -//! struct Foo { -//! pub bar: bool, -//! pub baz: u64, -//! } -//! -//! fn main() { -//! let foo = Foo { -//! bar: true, -//! baz: 42, -//! }; -//! -//! let bytes = ssz_encode(&foo); -//! -//! let (decoded_foo, _i) = Foo::ssz_decode(&bytes, 0).unwrap(); -//! -//! assert_eq!(foo.baz, decoded_foo.baz); -//! } -//! ``` +#![recursion_limit = "128"] extern crate proc_macro; use proc_macro::TokenStream; -use quote::{quote, ToTokens}; +use quote::quote; use syn::{parse_macro_input, DeriveInput}; -/// Returns a Vec of `syn::Ident` for each named field in the struct. -/// -/// # Panics -/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time. -fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> { - struct_data - .fields - .iter() - .map(|f| match &f.ident { - Some(ref ident) => ident, - _ => panic!("ssz_derive only supports named struct fields."), - }) - .collect() -} - /// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields /// that should not be serialized. /// @@ -80,6 +30,22 @@ fn get_serializable_named_field_idents<'a>( .collect() } +/// Returns a Vec of `syn::Type` for each named field in the struct, whilst filtering out fields +/// that should not be serialized. +fn get_serializable_field_types<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Type> { + struct_data + .fields + .iter() + .filter_map(|f| { + if should_skip_serializing(&f) { + None + } else { + Some(&f.ty) + } + }) + .collect() +} + /// Returns true if some field has an attribute declaring it should not be serialized. /// /// The field attribute is: `#[ssz(skip_serializing)]` @@ -92,7 +58,7 @@ fn should_skip_serializing(field: &syn::Field) -> bool { false } -/// Implements `ssz::Encodable` for some `struct`. +/// Implements `ssz::Encode` for some `struct`. /// /// Fields are encoded in the order they are defined. #[proc_macro_derive(Encode, attributes(ssz))] @@ -100,6 +66,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); let name = &item.ident; + let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl(); let struct_data = match &item.data { syn::Data::Struct(s) => s, @@ -107,13 +74,43 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { }; let field_idents = get_serializable_named_field_idents(&struct_data); + let field_types_a = get_serializable_field_types(&struct_data); + let field_types_b = field_types_a.clone(); + let field_types_c = field_types_a.clone(); let output = quote! { - impl ssz::Encodable for #name { - fn ssz_append(&self, s: &mut ssz::SszStream) { + impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { #( - s.append(&self.#field_idents); + <#field_types_a as ssz::Encode>::is_ssz_fixed_len() && )* + true + } + + fn ssz_fixed_len() -> usize { + if ::is_ssz_fixed_len() { + #( + <#field_types_b as ssz::Encode>::ssz_fixed_len() + + )* + 0 + } else { + ssz::BYTES_PER_LENGTH_OFFSET + } + } + + fn ssz_append(&self, buf: &mut Vec) { + let offset = #( + <#field_types_c as ssz::Encode>::ssz_fixed_len() + + )* + 0; + + let mut encoder = ssz::SszEncoder::container(buf, offset); + + #( + encoder.append(&self.#field_idents); + )* + + encoder.finalize(); } } }; @@ -132,7 +129,7 @@ fn should_skip_deserializing(field: &syn::Field) -> bool { false } -/// Implements `ssz::Decodable` for some `struct`. +/// Implements `ssz::Decode` for some `struct`. /// /// Fields are decoded in the order they are defined. #[proc_macro_derive(Decode)] @@ -140,27 +137,45 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); let name = &item.ident; + let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl(); let struct_data = match &item.data { syn::Data::Struct(s) => s, _ => panic!("ssz_derive only supports structs."), }; - let all_idents = get_named_field_idents(&struct_data); + let mut register_types = vec![]; + let mut decodes = vec![]; + let mut is_fixed_lens = vec![]; + let mut fixed_lens = vec![]; // Build quotes for fields that should be deserialized and those that should be built from // `Default`. - let mut quotes = vec![]; for field in &struct_data.fields { match &field.ident { Some(ref ident) => { if should_skip_deserializing(field) { - quotes.push(quote! { - let #ident = <_>::default(); + // Field should not be deserialized; use a `Default` impl to instantiate. + decodes.push(quote! { + #ident: <_>::default() }); } else { - quotes.push(quote! { - let (#ident, i) = <_>::ssz_decode(bytes, i)?; + let ty = &field.ty; + + register_types.push(quote! { + builder.register_type::<#ty>()?; + }); + + decodes.push(quote! { + #ident: decoder.decode_next()? + }); + + is_fixed_lens.push(quote! { + <#ty as ssz::Decode>::is_ssz_fixed_len() + }); + + fixed_lens.push(quote! { + <#ty as ssz::Decode>::ssz_fixed_len() }); } } @@ -169,176 +184,41 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { } let output = quote! { - impl ssz::Decodable for #name { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), ssz::DecodeError> { + impl #impl_generics ssz::Decode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { #( - #quotes + #is_fixed_lens && + )* + true + } + + fn ssz_fixed_len() -> usize { + if ::is_ssz_fixed_len() { + #( + #fixed_lens + + )* + 0 + } else { + ssz::BYTES_PER_LENGTH_OFFSET + } + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let mut builder = ssz::SszDecoderBuilder::new(bytes); + + #( + #register_types )* - Ok(( - Self { - #( - #all_idents, - )* - }, - i - )) - } - } - }; - output.into() -} + let mut decoder = builder.build()?; -/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields -/// that should not be tree hashed. -/// -/// # Panics -/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time. -fn get_tree_hashable_named_field_idents<'a>( - struct_data: &'a syn::DataStruct, -) -> Vec<&'a syn::Ident> { - struct_data - .fields - .iter() - .filter_map(|f| { - if should_skip_tree_hash(&f) { - None - } else { - Some(match &f.ident { - Some(ref ident) => ident, - _ => panic!("ssz_derive only supports named struct fields."), + Ok(Self { + #( + #decodes, + )* }) } - }) - .collect() -} - -/// Returns true if some field has an attribute declaring it should not be tree-hashed. -/// -/// The field attribute is: `#[tree_hash(skip_hashing)]` -fn should_skip_tree_hash(field: &syn::Field) -> bool { - for attr in &field.attrs { - if attr.into_token_stream().to_string() == "# [ tree_hash ( skip_hashing ) ]" { - return true; - } - } - false -} - -/// Implements `ssz::TreeHash` for some `struct`. -/// -/// Fields are processed in the order they are defined. -#[proc_macro_derive(TreeHash, attributes(tree_hash))] -pub fn ssz_tree_hash_derive(input: TokenStream) -> TokenStream { - let item = parse_macro_input!(input as DeriveInput); - - let name = &item.ident; - - let struct_data = match &item.data { - syn::Data::Struct(s) => s, - _ => panic!("ssz_derive only supports structs."), - }; - - let field_idents = get_tree_hashable_named_field_idents(&struct_data); - - let output = quote! { - impl ssz::TreeHash for #name { - fn hash_tree_root(&self) -> Vec { - let mut list: Vec> = Vec::new(); - #( - list.push(self.#field_idents.hash_tree_root()); - )* - - ssz::merkle_hash(&mut list) - } } }; output.into() } - -/// Returns `true` if some `Ident` should be considered to be a signature type. -fn type_ident_is_signature(ident: &syn::Ident) -> bool { - match ident.to_string().as_ref() { - "Signature" => true, - "AggregateSignature" => true, - _ => false, - } -} - -/// Takes a `Field` where the type (`ty`) portion is a path (e.g., `types::Signature`) and returns -/// the final `Ident` in that path. -/// -/// E.g., for `types::Signature` returns `Signature`. -fn final_type_ident(field: &syn::Field) -> &syn::Ident { - match &field.ty { - syn::Type::Path(path) => &path.path.segments.last().unwrap().value().ident, - _ => panic!("ssz_derive only supports Path types."), - } -} - -/// Implements `ssz::TreeHash` for some `struct`, whilst excluding any fields following and -/// including a field that is of type "Signature" or "AggregateSignature". -/// -/// See: -/// https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots -/// -/// This is a rather horrendous macro, it will read the type of the object as a string and decide -/// if it's a signature by matching that string against "Signature" or "AggregateSignature". So, -/// it's important that you use those exact words as your type -- don't alias it to something else. -/// -/// If you can think of a better way to do this, please make an issue! -/// -/// Fields are processed in the order they are defined. -#[proc_macro_derive(SignedRoot, attributes(signed_root))] -pub fn ssz_signed_root_derive(input: TokenStream) -> TokenStream { - let item = parse_macro_input!(input as DeriveInput); - - let name = &item.ident; - - let struct_data = match &item.data { - syn::Data::Struct(s) => s, - _ => panic!("ssz_derive only supports structs."), - }; - - let mut field_idents: Vec<&syn::Ident> = vec![]; - - let field_idents = get_signed_root_named_field_idents(&struct_data); - - let output = quote! { - impl ssz::SignedRoot for #name { - fn signed_root(&self) -> Vec { - let mut list: Vec> = Vec::new(); - #( - list.push(self.#field_idents.hash_tree_root()); - )* - - ssz::merkle_hash(&mut list) - } - } - }; - output.into() -} - -fn get_signed_root_named_field_idents(struct_data: &syn::DataStruct) -> Vec<&syn::Ident> { - struct_data - .fields - .iter() - .filter_map(|f| { - if should_skip_signed_root(&f) { - None - } else { - Some(match &f.ident { - Some(ref ident) => ident, - _ => panic!("ssz_derive only supports named struct fields"), - }) - } - }) - .collect() -} - -fn should_skip_signed_root(field: &syn::Field) -> bool { - field - .attrs - .iter() - .any(|attr| attr.into_token_stream().to_string() == "# [ signed_root ( skip_hashing ) ]") -} diff --git a/eth2/utils/ssz_derive/tests/test_derives.rs b/eth2/utils/ssz_derive/tests/test_derives.rs deleted file mode 100644 index e025dc3a5..000000000 --- a/eth2/utils/ssz_derive/tests/test_derives.rs +++ /dev/null @@ -1,94 +0,0 @@ -use ssz::{SignedRoot, TreeHash}; -use ssz_derive::{SignedRoot, TreeHash}; - -#[derive(TreeHash, SignedRoot)] -struct CryptoKitties { - best_kitty: u64, - worst_kitty: u8, - kitties: Vec, -} - -impl CryptoKitties { - fn new() -> Self { - CryptoKitties { - best_kitty: 9999, - worst_kitty: 1, - kitties: vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43], - } - } - - fn hash(&self) -> Vec { - let mut list: Vec> = Vec::new(); - list.push(self.best_kitty.hash_tree_root()); - list.push(self.worst_kitty.hash_tree_root()); - list.push(self.kitties.hash_tree_root()); - ssz::merkle_hash(&mut list) - } -} - -#[test] -fn test_cryptokitties_hash() { - let kitties = CryptoKitties::new(); - let expected_hash = vec![ - 201, 9, 139, 14, 24, 247, 21, 55, 132, 211, 51, 125, 183, 186, 177, 33, 147, 210, 42, 108, - 174, 162, 221, 227, 157, 179, 15, 7, 97, 239, 82, 220, - ]; - assert_eq!(kitties.hash(), expected_hash); -} - -#[test] -fn test_simple_tree_hash_derive() { - let kitties = CryptoKitties::new(); - assert_eq!(kitties.hash_tree_root(), kitties.hash()); -} - -#[test] -fn test_simple_signed_root_derive() { - let kitties = CryptoKitties::new(); - assert_eq!(kitties.signed_root(), kitties.hash()); -} - -#[derive(TreeHash, SignedRoot)] -struct Casper { - friendly: bool, - #[tree_hash(skip_hashing)] - friends: Vec, - #[signed_root(skip_hashing)] - dead: bool, -} - -impl Casper { - fn new() -> Self { - Casper { - friendly: true, - friends: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - dead: true, - } - } - - fn expected_signed_hash(&self) -> Vec { - let mut list = Vec::new(); - list.push(self.friendly.hash_tree_root()); - list.push(self.friends.hash_tree_root()); - ssz::merkle_hash(&mut list) - } - - fn expected_tree_hash(&self) -> Vec { - let mut list = Vec::new(); - list.push(self.friendly.hash_tree_root()); - list.push(self.dead.hash_tree_root()); - ssz::merkle_hash(&mut list) - } -} - -#[test] -fn test_annotated_tree_hash_derive() { - let casper = Casper::new(); - assert_eq!(casper.hash_tree_root(), casper.expected_tree_hash()); -} - -#[test] -fn test_annotated_signed_root_derive() { - let casper = Casper::new(); - assert_eq!(casper.signed_root(), casper.expected_signed_hash()); -} diff --git a/eth2/utils/ssz_derive/tests/tests.rs b/eth2/utils/ssz_derive/tests/tests.rs new file mode 100644 index 000000000..d58db3b62 --- /dev/null +++ b/eth2/utils/ssz_derive/tests/tests.rs @@ -0,0 +1,22 @@ +use ssz::Encode; +use ssz_derive::Encode; + +#[derive(Debug, PartialEq, Encode)] +pub struct Foo { + a: u16, + b: Vec, + c: u16, +} + +#[test] +fn encode() { + let foo = Foo { + a: 42, + b: vec![0, 1, 2, 3], + c: 11, + }; + + let bytes = vec![42, 0, 8, 0, 0, 0, 11, 0, 0, 1, 2, 3]; + + assert_eq!(foo.as_ssz_bytes(), bytes); +} diff --git a/eth2/utils/swap_or_not_shuffle/src/shuffle_list.rs b/eth2/utils/swap_or_not_shuffle/src/shuffle_list.rs index e7e1e18e6..f60d793f2 100644 --- a/eth2/utils/swap_or_not_shuffle/src/shuffle_list.rs +++ b/eth2/utils/swap_or_not_shuffle/src/shuffle_list.rs @@ -18,6 +18,8 @@ const TOTAL_SIZE: usize = SEED_SIZE + ROUND_SIZE + POSITION_WINDOW_SIZE; /// Credits to [@protolambda](https://github.com/protolambda) for defining this algorithm. /// /// Shuffles if `forwards == true`, otherwise un-shuffles. +/// It holds that: shuffle_list(shuffle_list(l, r, s, true), r, s, false) == l +/// and: shuffle_list(shuffle_list(l, r, s, false), r, s, true) == l /// /// Returns `None` under any of the following conditions: /// - `list_size == 0` diff --git a/eth2/utils/test_random_derive/src/lib.rs b/eth2/utils/test_random_derive/src/lib.rs index 7920ea695..a268161dd 100644 --- a/eth2/utils/test_random_derive/src/lib.rs +++ b/eth2/utils/test_random_derive/src/lib.rs @@ -21,6 +21,7 @@ fn should_use_default(field: &syn::Field) -> bool { pub fn test_random_derive(input: TokenStream) -> TokenStream { let derived_input = parse_macro_input!(input as DeriveInput); let name = &derived_input.ident; + let (impl_generics, ty_generics, where_clause) = &derived_input.generics.split_for_impl(); let struct_data = match &derived_input.data { syn::Data::Struct(s) => s, @@ -48,8 +49,8 @@ pub fn test_random_derive(input: TokenStream) -> TokenStream { } let output = quote! { - impl TestRandom for #name { - fn random_for_test(rng: &mut T) -> Self { + impl #impl_generics TestRandom for #name #ty_generics #where_clause { + fn random_for_test(rng: &mut impl rand::RngCore) -> Self { Self { #( #quotes diff --git a/eth2/utils/tree_hash/Cargo.toml b/eth2/utils/tree_hash/Cargo.toml new file mode 100644 index 000000000..7e23d2165 --- /dev/null +++ b/eth2/utils/tree_hash/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tree_hash" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dev-dependencies] +tree_hash_derive = { path = "../tree_hash_derive" } + +[dependencies] +ethereum-types = "0.5" +hashing = { path = "../hashing" } +int_to_bytes = { path = "../int_to_bytes" } diff --git a/eth2/utils/tree_hash/README.md b/eth2/utils/tree_hash/README.md new file mode 100644 index 000000000..0498bfc3e --- /dev/null +++ b/eth2/utils/tree_hash/README.md @@ -0,0 +1,76 @@ +# Tree hashing + +Provides both cached and non-cached tree hashing methods. + +## Standard Tree Hash + +```rust +use tree_hash_derive::TreeHash; + +#[derive(TreeHash)] +struct Foo { + a: u64, + b: Vec, +} + +fn main() { + let foo = Foo { + a: 42, + b: vec![1, 2, 3] + }; + + println!("root: {}", foo.tree_hash_root()); +} +``` + +## Cached Tree Hash + + +```rust +use tree_hash_derive::{TreeHash, CachedTreeHash}; + +#[derive(TreeHash, CachedTreeHash)] +struct Foo { + a: u64, + b: Vec, +} + +#[derive(TreeHash, CachedTreeHash)] +struct Bar { + a: Vec, + b: u64, +} + +fn main() { + let bar = Bar { + a: vec![ + Foo { + a: 42, + b: vec![1, 2, 3] + } + ], + b: 42 + }; + + let modified_bar = Bar { + a: vec![ + Foo { + a: 100, + b: vec![1, 2, 3, 4, 5, 6] + }, + Foo { + a: 42, + b: vec![] + } + ], + b: 99 + }; + + + let mut hasher = CachedTreeHasher::new(&bar).unwrap(); + hasher.update(&modified_bar).unwrap(); + + // Assert that the cached tree hash matches a standard tree hash. + assert_eq!(hasher.tree_hash_root(), modified_bar.tree_hash_root()); +} +``` diff --git a/eth2/utils/tree_hash/src/impls.rs b/eth2/utils/tree_hash/src/impls.rs new file mode 100644 index 000000000..42ea9add0 --- /dev/null +++ b/eth2/utils/tree_hash/src/impls.rs @@ -0,0 +1,166 @@ +use super::*; +use crate::merkleize::merkle_root; +use ethereum_types::H256; +use hashing::hash; +use int_to_bytes::int_to_bytes32; + +macro_rules! impl_for_bitsize { + ($type: ident, $bit_size: expr) => { + impl TreeHash for $type { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Basic + } + + fn tree_hash_packed_encoding(&self) -> Vec { + self.to_le_bytes().to_vec() + } + + fn tree_hash_packing_factor() -> usize { + HASHSIZE / ($bit_size / 8) + } + + #[allow(clippy::cast_lossless)] + fn tree_hash_root(&self) -> Vec { + int_to_bytes32(*self as u64) + } + } + }; +} + +impl_for_bitsize!(u8, 8); +impl_for_bitsize!(u16, 16); +impl_for_bitsize!(u32, 32); +impl_for_bitsize!(u64, 64); +impl_for_bitsize!(usize, 64); + +impl TreeHash for bool { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Basic + } + + fn tree_hash_packed_encoding(&self) -> Vec { + (*self as u8).tree_hash_packed_encoding() + } + + fn tree_hash_packing_factor() -> usize { + u8::tree_hash_packing_factor() + } + + fn tree_hash_root(&self) -> Vec { + int_to_bytes32(*self as u64) + } +} + +impl TreeHash for [u8; 4] { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Vector + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("bytesN should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("bytesN should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + merkle_root(&self[..]) + } +} + +impl TreeHash for H256 { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Vector + } + + fn tree_hash_packed_encoding(&self) -> Vec { + self.as_bytes().to_vec() + } + + fn tree_hash_packing_factor() -> usize { + 1 + } + + fn tree_hash_root(&self) -> Vec { + merkle_root(&self.as_bytes().to_vec()) + } +} + +macro_rules! impl_for_list { + ($type: ty) => { + impl TreeHash for $type + where + T: TreeHash, + { + fn tree_hash_type() -> TreeHashType { + TreeHashType::List + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("List should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("List should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + let mut root_and_len = Vec::with_capacity(HASHSIZE * 2); + root_and_len.append(&mut vec_tree_hash_root(self)); + root_and_len.append(&mut int_to_bytes32(self.len() as u64)); + + hash(&root_and_len) + } + } + }; +} + +impl_for_list!(Vec); +impl_for_list!(&[T]); + +pub fn vec_tree_hash_root(vec: &[T]) -> Vec +where + T: TreeHash, +{ + let leaves = match T::tree_hash_type() { + TreeHashType::Basic => { + let mut leaves = + Vec::with_capacity((HASHSIZE / T::tree_hash_packing_factor()) * vec.len()); + + for item in vec { + leaves.append(&mut item.tree_hash_packed_encoding()); + } + + leaves + } + TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => { + let mut leaves = Vec::with_capacity(vec.len() * HASHSIZE); + + for item in vec { + leaves.append(&mut item.tree_hash_root()) + } + + leaves + } + }; + + merkle_root(&leaves) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn bool() { + let mut true_bytes: Vec = vec![1]; + true_bytes.append(&mut vec![0; 31]); + + let false_bytes: Vec = vec![0; 32]; + + assert_eq!(true.tree_hash_root(), true_bytes); + assert_eq!(false.tree_hash_root(), false_bytes); + } + +} diff --git a/eth2/utils/tree_hash/src/lib.rs b/eth2/utils/tree_hash/src/lib.rs new file mode 100644 index 000000000..2554e70c3 --- /dev/null +++ b/eth2/utils/tree_hash/src/lib.rs @@ -0,0 +1,74 @@ +pub mod impls; +pub mod merkleize; + +pub const BYTES_PER_CHUNK: usize = 32; +pub const HASHSIZE: usize = 32; +pub const MERKLE_HASH_CHUNK: usize = 2 * BYTES_PER_CHUNK; + +#[derive(Debug, PartialEq, Clone)] +pub enum TreeHashType { + Basic, + Vector, + List, + Container, +} + +pub trait TreeHash { + fn tree_hash_type() -> TreeHashType; + + fn tree_hash_packed_encoding(&self) -> Vec; + + fn tree_hash_packing_factor() -> usize; + + fn tree_hash_root(&self) -> Vec; +} + +pub trait SignedRoot: TreeHash { + fn signed_root(&self) -> Vec; +} + +#[macro_export] +macro_rules! tree_hash_ssz_encoding_as_vector { + ($type: ident) => { + impl tree_hash::TreeHash for $type { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::Vector + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + tree_hash::merkleize::merkle_root(&ssz::ssz_encode(self)) + } + } + }; +} + +#[macro_export] +macro_rules! tree_hash_ssz_encoding_as_list { + ($type: ident) => { + impl tree_hash::TreeHash for $type { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::List + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("List should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("List should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + ssz::ssz_encode(self).tree_hash_root() + } + } + }; +} diff --git a/eth2/utils/tree_hash/src/merkleize.rs b/eth2/utils/tree_hash/src/merkleize.rs new file mode 100644 index 000000000..9482895ec --- /dev/null +++ b/eth2/utils/tree_hash/src/merkleize.rs @@ -0,0 +1,69 @@ +use super::*; +use hashing::hash; + +pub fn merkle_root(bytes: &[u8]) -> Vec { + // TODO: replace this with a more memory efficient method. + efficient_merkleize(&bytes)[0..32].to_vec() +} + +pub fn efficient_merkleize(bytes: &[u8]) -> Vec { + // If the bytes are just one chunk (or less than one chunk) just return them. + if bytes.len() <= HASHSIZE { + let mut o = bytes.to_vec(); + o.resize(HASHSIZE, 0); + return o; + } + + let leaves = num_sanitized_leaves(bytes.len()); + let nodes = num_nodes(leaves); + let internal_nodes = nodes - leaves; + + let num_bytes = std::cmp::max(internal_nodes, 1) * HASHSIZE + bytes.len(); + + let mut o: Vec = vec![0; internal_nodes * HASHSIZE]; + + o.append(&mut bytes.to_vec()); + + assert_eq!(o.len(), num_bytes); + + let empty_chunk_hash = hash(&[0; MERKLE_HASH_CHUNK]); + + let mut i = nodes * HASHSIZE; + let mut j = internal_nodes * HASHSIZE; + + while i >= MERKLE_HASH_CHUNK { + i -= MERKLE_HASH_CHUNK; + + j -= HASHSIZE; + let hash = match o.get(i..i + MERKLE_HASH_CHUNK) { + // All bytes are available, hash as ususal. + Some(slice) => hash(slice), + // Unable to get all the bytes. + None => { + match o.get(i..) { + // Able to get some of the bytes, pad them out. + Some(slice) => { + let mut bytes = slice.to_vec(); + bytes.resize(MERKLE_HASH_CHUNK, 0); + hash(&bytes) + } + // Unable to get any bytes, use the empty-chunk hash. + None => empty_chunk_hash.clone(), + } + } + }; + + o[j..j + HASHSIZE].copy_from_slice(&hash); + } + + o +} + +fn num_sanitized_leaves(num_bytes: usize) -> usize { + let leaves = (num_bytes + HASHSIZE - 1) / HASHSIZE; + leaves.next_power_of_two() +} + +fn num_nodes(num_leaves: usize) -> usize { + 2 * num_leaves - 1 +} diff --git a/eth2/utils/tree_hash_derive/Cargo.toml b/eth2/utils/tree_hash_derive/Cargo.toml new file mode 100644 index 000000000..8544108a7 --- /dev/null +++ b/eth2/utils/tree_hash_derive/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tree_hash_derive" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" +description = "Procedural derive macros for SSZ tree hashing." + +[lib] +proc-macro = true + +[dev-dependencies] +tree_hash = { path = "../tree_hash" } +cached_tree_hash = { path = "../cached_tree_hash" } + +[dependencies] +syn = "0.15" +quote = "0.6" diff --git a/eth2/utils/tree_hash_derive/src/lib.rs b/eth2/utils/tree_hash_derive/src/lib.rs new file mode 100644 index 000000000..fe94af181 --- /dev/null +++ b/eth2/utils/tree_hash_derive/src/lib.rs @@ -0,0 +1,212 @@ +#![recursion_limit = "256"] +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::{quote, ToTokens}; +use syn::{parse_macro_input, DeriveInput}; + +/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields +/// that should not be hashed. +/// +/// # Panics +/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time. +fn get_hashable_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> { + struct_data + .fields + .iter() + .filter_map(|f| { + if should_skip_hashing(&f) { + None + } else { + Some(match &f.ident { + Some(ref ident) => ident, + _ => panic!("tree_hash_derive only supports named struct fields."), + }) + } + }) + .collect() +} + +/// Returns true if some field has an attribute declaring it should not be hashedd. +/// +/// The field attribute is: `#[tree_hash(skip_hashing)]` +fn should_skip_hashing(field: &syn::Field) -> bool { + field + .attrs + .iter() + .any(|attr| attr.into_token_stream().to_string() == "# [ tree_hash ( skip_hashing ) ]") +} + +/// Implements `tree_hash::CachedTreeHash` for some `struct`. +/// +/// Fields are hashed in the order they are defined. +#[proc_macro_derive(CachedTreeHash, attributes(tree_hash))] +pub fn subtree_derive(input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as DeriveInput); + let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl(); + + let name = &item.ident; + + let struct_data = match &item.data { + syn::Data::Struct(s) => s, + _ => panic!("tree_hash_derive only supports structs."), + }; + + let idents_a = get_hashable_named_field_idents(&struct_data); + let idents_b = idents_a.clone(); + let idents_c = idents_a.clone(); + + let output = quote! { + impl #impl_generics cached_tree_hash::CachedTreeHash for #name #ty_generics #where_clause { + fn new_tree_hash_cache(&self, depth: usize) -> Result { + let tree = cached_tree_hash::TreeHashCache::from_subtrees( + self, + vec![ + #( + self.#idents_a.new_tree_hash_cache(depth)?, + )* + ], + depth + )?; + + Ok(tree) + } + + fn num_tree_hash_cache_chunks(&self) -> usize { + cached_tree_hash::BTreeOverlay::new(self, 0, 0).num_chunks() + } + + fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema { + let mut lengths = vec![]; + + #( + lengths.push(self.#idents_b.num_tree_hash_cache_chunks()); + )* + + cached_tree_hash::BTreeSchema::from_lengths(depth, lengths) + } + + fn update_tree_hash_cache(&self, cache: &mut cached_tree_hash::TreeHashCache) -> Result<(), cached_tree_hash::Error> { + let overlay = cached_tree_hash::BTreeOverlay::new(self, cache.chunk_index, 0); + + + // Skip the chunk index to the first leaf node of this struct. + cache.chunk_index = overlay.first_leaf_node(); + // Skip the overlay index to the first leaf node of this struct. + // cache.overlay_index += 1; + + // Recurse into the struct items, updating their caches. + #( + self.#idents_c.update_tree_hash_cache(cache)?; + )* + + // Iterate through the internal nodes, updating them if their children have changed. + cache.update_internal_nodes(&overlay)?; + + cache.chunk_index = overlay.next_node(); + + Ok(()) + } + } + }; + output.into() +} + +/// Implements `tree_hash::TreeHash` for some `struct`. +/// +/// Fields are hashed in the order they are defined. +#[proc_macro_derive(TreeHash, attributes(tree_hash))] +pub fn tree_hash_derive(input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as DeriveInput); + + let name = &item.ident; + let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl(); + + let struct_data = match &item.data { + syn::Data::Struct(s) => s, + _ => panic!("tree_hash_derive only supports structs."), + }; + + let idents = get_hashable_named_field_idents(&struct_data); + + let output = quote! { + impl #impl_generics tree_hash::TreeHash for #name #ty_generics #where_clause { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::Container + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + let mut leaves = Vec::with_capacity(4 * tree_hash::HASHSIZE); + + #( + leaves.append(&mut self.#idents.tree_hash_root()); + )* + + tree_hash::merkleize::merkle_root(&leaves) + } + } + }; + output.into() +} + +#[proc_macro_derive(SignedRoot, attributes(signed_root))] +pub fn tree_hash_signed_root_derive(input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as DeriveInput); + + let name = &item.ident; + + let struct_data = match &item.data { + syn::Data::Struct(s) => s, + _ => panic!("tree_hash_derive only supports structs."), + }; + + let idents = get_signed_root_named_field_idents(&struct_data); + let num_elems = idents.len(); + + let output = quote! { + impl tree_hash::SignedRoot for #name { + fn signed_root(&self) -> Vec { + let mut leaves = Vec::with_capacity(#num_elems * tree_hash::HASHSIZE); + + #( + leaves.append(&mut self.#idents.tree_hash_root()); + )* + + tree_hash::merkleize::merkle_root(&leaves) + } + } + }; + output.into() +} + +fn get_signed_root_named_field_idents(struct_data: &syn::DataStruct) -> Vec<&syn::Ident> { + struct_data + .fields + .iter() + .filter_map(|f| { + if should_skip_signed_root(&f) { + None + } else { + Some(match &f.ident { + Some(ref ident) => ident, + _ => panic!("tree_hash_derive only supports named struct fields"), + }) + } + }) + .collect() +} + +fn should_skip_signed_root(field: &syn::Field) -> bool { + field + .attrs + .iter() + .any(|attr| attr.into_token_stream().to_string() == "# [ signed_root ( skip_hashing ) ]") +} diff --git a/eth2/utils/tree_hash_derive/tests/tests.rs b/eth2/utils/tree_hash_derive/tests/tests.rs new file mode 100644 index 000000000..d4fd55165 --- /dev/null +++ b/eth2/utils/tree_hash_derive/tests/tests.rs @@ -0,0 +1,179 @@ +use cached_tree_hash::{CachedTreeHash, TreeHashCache}; +use tree_hash::{merkleize::merkle_root, SignedRoot, TreeHash}; +use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash}; + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct Inner { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, +} + +fn test_standard_and_cached(original: &T, modified: &T) { + // let mut cache = original.new_tree_hash_cache().unwrap(); + let mut cache = TreeHashCache::new(original).unwrap(); + + let standard_root = original.tree_hash_root(); + let cached_root = cache.tree_hash_root().unwrap(); + assert_eq!(standard_root, cached_root); + + // Test after a modification + cache.update(modified).unwrap(); + let standard_root = modified.tree_hash_root(); + let cached_root = cache.tree_hash_root().unwrap(); + assert_eq!(standard_root, cached_root); +} + +#[test] +fn inner_standard_vs_cached() { + let original = Inner { + a: 1, + b: 2, + c: 3, + d: 4, + }; + let modified = Inner { + b: 42, + ..original.clone() + }; + + test_standard_and_cached(&original, &modified); +} + +#[derive(Clone, Debug, TreeHash, CachedTreeHash)] +pub struct Uneven { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, + pub e: u64, +} + +#[test] +fn uneven_standard_vs_cached() { + let original = Uneven { + a: 1, + b: 2, + c: 3, + d: 4, + e: 5, + }; + let modified = Uneven { + e: 42, + ..original.clone() + }; + + test_standard_and_cached(&original, &modified); +} + +#[derive(Clone, Debug, TreeHash, SignedRoot)] +pub struct SignedInner { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, + #[signed_root(skip_hashing)] + pub e: u64, +} + +#[test] +fn signed_root() { + let unsigned = Inner { + a: 1, + b: 2, + c: 3, + d: 4, + }; + let signed = SignedInner { + a: 1, + b: 2, + c: 3, + d: 4, + e: 5, + }; + + assert_eq!(unsigned.tree_hash_root(), signed.signed_root()); +} + +#[derive(TreeHash, SignedRoot)] +struct CryptoKitties { + best_kitty: u64, + worst_kitty: u8, + kitties: Vec, +} + +impl CryptoKitties { + fn new() -> Self { + CryptoKitties { + best_kitty: 9999, + worst_kitty: 1, + kitties: vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43], + } + } + + fn hash(&self) -> Vec { + let mut leaves = vec![]; + leaves.append(&mut self.best_kitty.tree_hash_root()); + leaves.append(&mut self.worst_kitty.tree_hash_root()); + leaves.append(&mut self.kitties.tree_hash_root()); + merkle_root(&leaves) + } +} + +#[test] +fn test_simple_tree_hash_derive() { + let kitties = CryptoKitties::new(); + assert_eq!(kitties.tree_hash_root(), kitties.hash()); +} + +#[test] +fn test_simple_signed_root_derive() { + let kitties = CryptoKitties::new(); + assert_eq!(kitties.signed_root(), kitties.hash()); +} + +#[derive(TreeHash, SignedRoot)] +struct Casper { + friendly: bool, + #[tree_hash(skip_hashing)] + friends: Vec, + #[signed_root(skip_hashing)] + dead: bool, +} + +impl Casper { + fn new() -> Self { + Casper { + friendly: true, + friends: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + dead: true, + } + } + + fn expected_signed_hash(&self) -> Vec { + let mut list = Vec::new(); + list.append(&mut self.friendly.tree_hash_root()); + list.append(&mut self.friends.tree_hash_root()); + merkle_root(&list) + } + + fn expected_tree_hash(&self) -> Vec { + let mut list = Vec::new(); + list.append(&mut self.friendly.tree_hash_root()); + list.append(&mut self.dead.tree_hash_root()); + merkle_root(&list) + } +} + +#[test] +fn test_annotated_tree_hash_derive() { + let casper = Casper::new(); + assert_eq!(casper.tree_hash_root(), casper.expected_tree_hash()); +} + +#[test] +fn test_annotated_signed_root_derive() { + let casper = Casper::new(); + assert_eq!(casper.signed_root(), casper.expected_signed_hash()); +} diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index 80477c8ea..559460c8b 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -13,10 +13,9 @@ name = "validator_client" path = "src/lib.rs" [dependencies] -block_proposer = { path = "../eth2/block_proposer" } -attester = { path = "../eth2/attester" } bls = { path = "../eth2/utils/bls" } ssz = { path = "../eth2/utils/ssz" } +tree_hash = { path = "../eth2/utils/tree_hash" } clap = "2.32.0" dirs = "1.0.3" grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] } diff --git a/validator_client/README.md b/validator_client/README.md index 03979fbb8..e6a01007a 100644 --- a/validator_client/README.md +++ b/validator_client/README.md @@ -75,8 +75,9 @@ The configuration directory structure looks like: Where the hex value of the directory is a portion of the validator public key. -Validator keys must be generated using the separate `accounts_manager` binary, which will +Validator keys must be generated using the separate `account_manager` binary, which will place the keys into this directory structure in a format compatible with the validator client. +Be sure to check the readme for `account_manager`. The chain specification (slot length, BLS domain, etc.) defaults to foundation parameters, however is temporary and an upgrade will allow these parameters to be diff --git a/validator_client/src/attestation_producer/grpc.rs b/validator_client/src/attestation_producer/grpc.rs index 900a92f32..9ac0a433f 100644 --- a/validator_client/src/attestation_producer/grpc.rs +++ b/validator_client/src/attestation_producer/grpc.rs @@ -1,7 +1,7 @@ use super::beacon_node_attestation::BeaconNodeAttestation; use crate::block_producer::{BeaconNodeError, PublishOutcome}; use protos::services_grpc::AttestationServiceClient; -use ssz::{ssz_encode, Decodable}; +use ssz::{Decode, Encode}; use protos::services::{ Attestation as GrpcAttestation, ProduceAttestationDataRequest, PublishAttestationRequest, @@ -22,8 +22,8 @@ impl BeaconNodeAttestation for AttestationServiceClient { .produce_attestation_data(&req) .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - let (attestation_data, _index) = - AttestationData::ssz_decode(reply.get_attestation_data().get_ssz(), 0) + let attestation_data = + AttestationData::from_ssz_bytes(reply.get_attestation_data().get_ssz()) .map_err(|_| BeaconNodeError::DecodeFailure)?; Ok(attestation_data) } @@ -34,7 +34,7 @@ impl BeaconNodeAttestation for AttestationServiceClient { ) -> Result { let mut req = PublishAttestationRequest::new(); - let ssz = ssz_encode(&attestation); + let ssz = attestation.as_ssz_bytes(); let mut grpc_attestation = GrpcAttestation::new(); grpc_attestation.set_ssz(ssz); diff --git a/validator_client/src/attestation_producer/mod.rs b/validator_client/src/attestation_producer/mod.rs index 0fbc7bcba..d2dbdf2e2 100644 --- a/validator_client/src/attestation_producer/mod.rs +++ b/validator_client/src/attestation_producer/mod.rs @@ -8,7 +8,7 @@ use super::block_producer::{BeaconNodeError, PublishOutcome, ValidatorEvent}; use crate::signer::Signer; use beacon_node_attestation::BeaconNodeAttestation; use slog::{error, info, warn}; -use ssz::TreeHash; +use tree_hash::TreeHash; use types::{ AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, AttestationDuty, Bitfield, @@ -123,7 +123,7 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { data: attestation.clone(), custody_bit: false, } - .hash_tree_root(); + .tree_hash_root(); let sig = self.signer.sign_message(&message, domain)?; diff --git a/validator_client/src/block_producer/grpc.rs b/validator_client/src/block_producer/grpc.rs index 1c4977bac..820fbdb66 100644 --- a/validator_client/src/block_producer/grpc.rs +++ b/validator_client/src/block_producer/grpc.rs @@ -3,7 +3,7 @@ use protos::services::{ BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, }; use protos::services_grpc::BeaconBlockServiceClient; -use ssz::{decode, ssz_encode}; +use ssz::{Decode, Encode}; use std::sync::Arc; use types::{BeaconBlock, Signature, Slot}; @@ -33,7 +33,7 @@ impl BeaconNodeBlock for BeaconBlockGrpcClient { // request a beacon block from the node let mut req = ProduceBeaconBlockRequest::new(); req.set_slot(slot.as_u64()); - req.set_randao_reveal(ssz_encode(randao_reveal)); + req.set_randao_reveal(randao_reveal.as_ssz_bytes()); //TODO: Determine if we want an explicit timeout let reply = self @@ -46,7 +46,8 @@ impl BeaconNodeBlock for BeaconBlockGrpcClient { let block = reply.get_block(); let ssz = block.get_ssz(); - let block = decode::(&ssz).map_err(|_| BeaconNodeError::DecodeFailure)?; + let block = + BeaconBlock::from_ssz_bytes(&ssz).map_err(|_| BeaconNodeError::DecodeFailure)?; Ok(Some(block)) } else { @@ -61,7 +62,7 @@ impl BeaconNodeBlock for BeaconBlockGrpcClient { fn publish_beacon_block(&self, block: BeaconBlock) -> Result { let mut req = PublishBeaconBlockRequest::new(); - let ssz = ssz_encode(&block); + let ssz = block.as_ssz_bytes(); let mut grpc_block = GrpcBeaconBlock::new(); grpc_block.set_ssz(ssz); diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 8b4f5abda..2689b302d 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -6,8 +6,8 @@ pub use self::beacon_node_block::{BeaconNodeError, PublishOutcome}; pub use self::grpc::BeaconBlockGrpcClient; use crate::signer::Signer; use slog::{error, info, warn}; -use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; +use tree_hash::{SignedRoot, TreeHash}; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; #[derive(Debug, PartialEq)] @@ -86,7 +86,7 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { pub fn produce_block(&mut self) -> Result { let epoch = self.slot.epoch(self.spec.slots_per_epoch); - let message = epoch.hash_tree_root(); + let message = epoch.tree_hash_root(); let randao_reveal = match self.signer.sign_message( &message, self.spec.get_domain(epoch, Domain::Randao, &self.fork), diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 903da047e..1e9450d59 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -6,7 +6,9 @@ use std::fs; use std::fs::File; use std::io::{Error, ErrorKind}; use std::path::PathBuf; -use types::ChainSpec; +use types::{ + ChainSpec, EthSpec, FewValidatorsEthSpec, FoundationEthSpec, LighthouseTestnetEthSpec, +}; /// Stores the core configuration for this validator instance. #[derive(Clone)] @@ -31,7 +33,7 @@ impl Default for Config { let server = "localhost:5051".to_string(); - let spec = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); Self { data_dir, @@ -65,9 +67,9 @@ impl Config { if let Some(spec_str) = args.value_of("spec") { info!(log, "Using custom spec: {:?}", spec_str); config.spec = match spec_str { - "foundation" => ChainSpec::foundation(), - "few_validators" => ChainSpec::few_validators(), - "lighthouse_testnet" => ChainSpec::lighthouse_testnet(), + "foundation" => FoundationEthSpec::spec(), + "few_validators" => FewValidatorsEthSpec::spec(), + "lighthouse_testnet" => LighthouseTestnetEthSpec::spec(), // Should be impossible due to clap's `possible_values(..)` function. _ => unreachable!(), }; diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 7db4672e3..b2ddfd0b0 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -51,7 +51,7 @@ impl DutiesManager { /// /// be a wall-clock (e.g., system time, remote server time, etc.). fn update(&self, epoch: Epoch) -> Result { - let public_keys: Vec = self.signers.iter().map(|s| s.to_public()).collect(); + let public_keys: Vec = self.signers.iter().map(Signer::to_public).collect(); let duties = self.beacon_node.request_duties(epoch, &public_keys)?; { // If these duties were known, check to see if they're updates or identical. diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index 7a353e0dc..038399936 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -7,9 +7,9 @@ mod service; mod signer; use crate::config::Config as ValidatorClientConfig; +use crate::service::Service as ValidatorService; use clap::{App, Arg}; use protos::services_grpc::ValidatorServiceClient; -use service::Service as ValidatorService; use slog::{error, info, o, Drain}; use types::Keypair; diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index a8a8325dd..a340f99fc 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -31,7 +31,6 @@ use tokio::prelude::*; use tokio::runtime::Builder; use tokio::timer::Interval; use tokio_timer::clock::Clock; -use types::test_utils::generate_deterministic_keypairs; use types::{ChainSpec, Epoch, Fork, Slot}; /// A fixed amount of time after a slot to perform operations. This gives the node time to complete @@ -166,11 +165,15 @@ impl Service { /* Generate the duties manager */ - // generate keypairs + // Load generated keypairs + let keypairs = match config.fetch_keys(&log) { + Some(kps) => Arc::new(kps), + None => panic!("No key pairs found, cannot start validator client without at least one. Try running `./account_manager generate` first.") + }; // TODO: keypairs are randomly generated; they should be loaded from a file or generated. // https://github.com/sigp/lighthouse/issues/160 - let keypairs = Arc::new(generate_deterministic_keypairs(8)); + //let keypairs = Arc::new(generate_deterministic_keypairs(8)); // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty) // where EpochDuty contains slot numbers and attestation data that each validator needs to